EOFException while reading from socket in chat program...

Hi,

I'm doing a chat program. In this the user can opt to choose their own user name and when they attempt to login, if the user name is already taken, then an error frame is sent to the user, otherwise loginsuccess frame will be sent to the user.

I have 2 classes FrameReader and FrameWriter which writes and reads the frame from respective streams.

Server will have one thread to do write operations and 1 read thread for every client who logged in. The thread which writes data to the stream, takes data from arrayblockingqueue.

ServerWriterThread st =new ServerWriterThread(this.buffer);

// no need to start the thread

// it is automatically started by the constructor

try{

ServerSocket ss =new ServerSocket(ServerProperties.port,ServerProperties.maxUsers);

while(!shouldServerShutDown){

Logger.log("listening @ " + ss.getLocalPort());

Socket s = ss.accept();

DataInputStream inStream =new DataInputStream(s.getInputStream());

DataOutputStream outStream =new DataOutputStream(s.getOutputStream());

FrameReader reader =new FrameReader(inStream);

Frame frame = reader.readFrame();

switch(frame.getCommand()){

case FreeTalkServerConstants.LOGIN:

User u =new User(frame.getFromAddress(),s);

try{

UserManager.getInstance().addUser(u);

Logger.log("New user : " + u);

this.buffer.add(

new WriteRequestObject(

FrameAssembler.generateLoginSuccessFrame(u.getUserName()),

u.getDataOutputStream())

);

UserThread ut =new UserThread(s,this);// constructor itself will start the thread

threadMap.put(u,ut);

//UserManager.getInstance().postNewUserToAll(u);

}catch (UserExistException e){

// do nothing with the user exist exception..

// but send back a error frame to the user

this.buffer.add(

new WriteRequestObject(

FrameAssembler.generateUserExistErrorFrame(u.getUserName()),

u.getDataOutputStream())

);

}

break;

case FreeTalkServerConstants.LOGOUT:// will not come here

break;

}

}

}catch(BindException be){

be.printStackTrace();

Logger.log("Server shutting down.. port in use");

this.requestServerShutDown();

System.exit(0);

}

catch (IOException e){

if(ServerProperties.isDebugMode)

e.printStackTrace();

}

END OF SERVER THREAD --

// This is the thread in the server for each user. this threads reads data from client stream

ublicclass UserThreadextends Threadimplements MessageReceiver<String>{

private Socket socket =null;

private ServerThread st =null;

privateboolean canQuit =false;

UserThread(Socket s,ServerThread st){

this.socket = s;

this.st = st;

this.start();

}

// each user will have a read thread

publicvoid run(){

ServerReadFrameProcessor frameProcessor =new ServerReadFrameProcessor(st,socket);

FrameReader fReader =null;

Frame f =null;

try{

fReader =new FrameReader(new DataInputStream(socket.getInputStream()));

while(!canQuit){

f = fReader.readFrame();

if(f!=null)

frameProcessor.processFrame(f);

}

}catch (IOException e1){

e1.printStackTrace();

}

}

public ServerThread getServerThread(){

return st;

}

publicvoid setServerThread(ServerThread st){

this.st = st;

}

public Socket getSocket(){

return socket;

}

publicvoid setSocket(Socket s){

this.socket = s;

}

publicvoid messageReceived(String e){

if(e.equals("quit")){

canQuit =true;

}

}

}

This is frame readerclass

publicclass FrameReaderimplements FreeTalkServerConstants{

private DataInputStream din =null;

public FrameReader(DataInputStream din){

this.din = din;

}

public FrameReader(){

this.din =null;

}

publicvoid setInputStream(DataInputStream din){

this.din = din;

}

public Frame readFrame()throws IOException{

int readSize = 0;

int totalRead = 0;

Frame f =new Frame();

int command = 0;

/*

* static final int LOGIN = 1;

static final int LOGOUT = 2;

static final int SEND_MSG = 3;

static final int RCV_MSG = 4;

static final int SEND_BIN_DATA = 5;

static final int RCV_BIN_DATA = 6;

static final int ERROR = 7;

static final int FILE_SEND_REQ = 8;

static final int FILE_SEND_ACCEPT = 9;

static final int FILE_SEND_REJECT = 10;

static final int FILE_SEND_COMPLETE = 11;

static final int FILE_SEND_SUCCESS = 12;

*/

synchronized(this.din){// only 1 thread can read data from a stream !!!

//if(din.available()>0) {

f.setFromAddress(din.readUTF());// THIS WHERE I'M GETTING EOF EXCEPTION

System.out.println(">" + f.getFromAddress());

f.setToAddress(din.readUTF());

System.out.println(">" + f.getToAddress());

command = din.readInt();

System.out.println(">" + command);

f.setCommand(command);

// -- differentiate the frame with "command" -- //

//-- Login Frame -- //

// -- Both From to will be same -- //

// --

switch(command){

case LOGIN:

break;

case LOGOUT:

break;

case SEND_MSG:

break;

case RCV_MSG:

break;

case LOGIN_SUCCESS:

break;

}

return f;

//} else {

//return null;

//}

}

}

}

STACK Trace :

java.io.EOFException

at java.io.DataInputStream.readUnsignedShort(Unknown Source)

at java.io.DataInputStream.readUTF(Unknown Source)

at java.io.DataInputStream.readUTF(Unknown Source)

at com.common.FrameReader.readFrame(FrameReader.java:58)

at com.server.main.UserThread.run(UserThread.java:31)

and this problem is not occuring always.. but sometimes...

what gone wrong in my code ?

[11147 byte] By [chaos_begins_herea] at [2007-11-26 14:14:15]
# 1
The peer has closed the socket. You are trying to readUTF() something that hasn't been written. You have an error in your application protocol implementation somewhere.
ejpa at 2007-7-8 2:03:36 > top of Java-index,Core,Core APIs...
# 2

Ok. Let me explain what I have done in little details..

1. client attempts to send a LOGIN frame.

2. If client is accepted then server will respond with LOGIN OK frame.

3. if client wants to logout it will send LOGOUT frame and close all the stream resources after flushing.

4. when the server receives the LOGOUT frame, it removes the user from the list.

There is no error in the client implementation. This I came to know by using ethereal (packet sniffer). When a client sends a LOGOUT frame it reaches the server machine correctly..

I'm getting the above exception only when the user attempts to LOGOUT.

Eventhough the server receives the packet, it is not being processed.

By the way, If "din.readUTF()" doesn't have a data in stream, then it will wait until it gets. Then how EOFException is thrown or under what circumstances this will be thrown.

When I inspected by setting the break points, if found that din.readUTF() waits indefinitely.

What could be the problem? I'm not able to figure out...

chaos_begins_herea at 2007-7-8 2:03:37 > top of Java-index,Core,Core APIs...
# 3

Frame reading protocol is slightly modified from what is shown above:

public class FrameReader implements FreeTalkServerConstants {

private DataInputStream din = null;

public FrameReader(DataInputStream din) {

this.din = din;

}

public FrameReader() {

this.din = null;

}

public void setInputStream(DataInputStream din) {

this.din = din;

}

public Frame readFrame() throws IOException {

int readSize = 0;

int totalRead = 0;

Frame f = new Frame();

int command = 0;

String chatMessage = "";

/*

* static final int LOGIN = 1;

static final int LOGOUT = 2;

static final int SEND_MSG = 3;

static final int RCV_MSG = 4;

static final int SEND_BIN_DATA = 5;

static final int RCV_BIN_DATA = 6;

static final int ERROR = 7;

static final int FILE_SEND_REQ = 8;

static final int FILE_SEND_ACCEPT = 9;

static final int FILE_SEND_REJECT = 10;

static final int FILE_SEND_COMPLETE = 11;

static final int FILE_SEND_SUCCESS = 12;

*/

synchronized(this.din) { // only 1 thread can read data from a stream !!!

System.out.println("fetching getFromAddres ..");

f.setFromAddress(din.readUTF());

String data = Thread.currentThread().getName()+">";

System.out.println(data + f.getFromAddress());

f.setToAddress(din.readUTF());

System.out.println(data + f.getToAddress());

command = din.readInt();

System.out.println(data + command);

f.setCommand(command);

f.setChatMessage(din.readUTF());

System.out.println(data + f.getChatMessage());

// -- differentiate the frame with "command" -- //

//-- Login Frame -- //

// -- Both From to will be same -- //

// --

switch(command) {

case LOGIN:

break;

case LOGOUT:

break;

case SEND_MSG:

break;

case RCV_MSG:

break;

case LOGIN_SUCCESS:

break;

}

return f;

//} else {

//return null;

//}

}

}

}

When I run the code, server waits indefinitely after

printing "fetching getFromAddres". Even though required data is successfully received by the amchine..

Message was edited by:

chaos_begins_here to give more info

chaos_begins_herea at 2007-7-8 2:03:37 > top of Java-index,Core,Core APIs...
# 4
im rather new to java, but i had a similar problem with an eofexception. it turned out to occur because i had forgotten to flush and close an outputstream before trying to read from the file created. so maybe you should check your code for mistakes with the streams.
HeistBastian84a at 2007-7-8 2:03:37 > top of Java-index,Core,Core APIs...
# 5
You'd better show us your client code.
ejpa at 2007-7-8 2:03:37 > top of Java-index,Core,Core APIs...
# 6

@ HeistBastian84 :

Yes I did that. when ever I write a Frame in a stream, i flush it before closing.

@ejb:

client :

MainWindow : MainWindow gui for client.

1. Get the connected socket and get outstream and instream for it.

2. Send out login frame.

3. wait to read the frame.

4. if the response is "LOGIN OK", then display login success

5. if the response is "USER EXIST" frame, then display user name already taken.

6. If the login is success then create 2 threads, 1 to read from the stream and other to write into stream

7. readerThread take a frameProcessor object which will handle the received frame

8. writherThread takes "WriteRequestObject" object

WriteRequestObject consists of two parameters, Socket on which to write, Frame to write.

The same object is used by server thread also

9. on the client side we are always going to write to the same socket.

code snippets :

public void doLogin(String uid,String server,int port) {

// attempt to login by connecting to the server ...

writerThread = null;

readerThread = null;

try {

// open connection

serverAddress = server;

serverPort = port;

Logger.log("client attempting to login with uid:"+uid+" @ " + server+":"+port);

Socket s = new Socket(server,port);

// do the ground work of getting the streams

// before sending login frame to the server

DataInputStream din = new DataInputStream(s.getInputStream());

DataOutputStream dout = new DataOutputStream(s.getOutputStream());

FrameWriter frameWriter = new FrameWriter(dout);

Frame loginFrame = FrameAssembler.generateLoginFrame(uid);

frameWriter.writeFrame(loginFrame);

FrameReader frameReader = new FrameReader(din);

Frame readFrame = frameReader.readFrame();

switch(readFrame.getCommand()) {

case FreeTalkServerConstants.USER_EXIST_ERROR:

JOptionPane.showMessageDialog(this,"User name already taken. Give a different name.");

this.login.setEnabled(true);

return;

case FreeTalkServerConstants.LOGIN_SUCCESS:

userId = uid;

this.canQuit = false;

JOptionPane.showMessageDialog(this,"Login Success");

this.quit.setEnabled(true);

break;

}

// delegate a frame processor to take care of the read frames

// this thread reads frame from the stream and ask the

// frame processor to handle it !

isUserLoggedIn = true;

readFrameProcessor = new ClientReadFrameProcessor(this);

// Thread which reads from the server and requests a frame processor

// to handle the frame.

readerThread = new Thread(new UserReaderThread(din,this,readFrameProcessor));

readerThread.start();

// WriterThread is the thread, which reads the data from the data queue and

// writes it on the outstream...

// multiple Thread will write inot the data queue from which writeThread is

//reading...

// Queue's buffer size bounded to prevent server from getting

// overloaded....

writerThread = new Thread(new UserWriterThread(dout,this,buffer));

writerThread.start();

Logger.log("new reader&writer thread spawn for " + uid);

// writer Thread reads from the queue and writes data to the server

}catch(IOException ioe) {

ioe.printStackTrace();

}

}

One minor flaw in my implementation is I run the doLogin(..) method in the AWT-THREAD itself, which cause client to

hang or it dones't repaint itself until it gets the response frame. (not relevant to our discussion)

public class UserReaderThread implements Runnable {

private DataInputStream inStream = null;

private MainWindow owner = null;

private FrameProcessor frameProcessor = null;

public UserReaderThread(DataInputStream in,MainWindow owner,

FrameProcessor processor) {

inStream = in;

this.owner = owner;

this.frameProcessor = processor;

}

public UserReaderThread() {

}

public void run() {

FrameReader reader = new FrameReader(inStream,"ser_read");

System.out.println("");

Frame f = null;

while(!owner.getQuitStatus()) { // will be true when you request quit...

int command = -1;

try {

f = reader.readFrame();

this.frameProcessor.processFrame(f);

// once the current frame has been processed

// receive next frame..

} catch(java.net.SocketException se) {

se.printStackTrace();

owner.requestClientShutDown();

}

catch(IOException e) {

owner.requestClientShutDown();

e.printStackTrace();

} finally {

if(this.inStream!=null) {

try {

this.inStream.close();

this.inStream = null;

Logger.log("stream shut...");

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

// accessor method not shown

// RUN METHOD OF USER WRITER THREAD, WHICH WRITES DATA INOT STREAM //

public void run() {

WriteRequestObject reqObj = null;

try {

while(!owner.getQuitStatus()) { // will true when requested to quit

Logger.log("attempting to read buffer...");

reqObj = buffer.take();

//frameWriter.setDataOutputStream(reqObj.getOutStream());

Logger.log("written to server:"+reqObj.getFrameToWrite().toString());

frameWriter.writeFrame(reqObj.getFrameToWrite());

}

}catch(InterruptedException ie) {

ie.printStackTrace();

}catch(IOException e) {

e.printStackTrace();

}finally {

// Since logout frame is the last frame close the stream after flushing

if(reqObj.getFrameToWrite().getCommand()==FreeTalkServerConstants.LOGOUT)

frameWriter.closeAndFlush();

else // if not just flush it.

frameWriter.flush();

} // finally

}

One more observation :

1. Let the user login. (Works fine)

2. Let the user logout. (Works fine)

3. Let ther user login again (works fine)

4. Let the user logout (doesn't work, server is not

reading the logout frame)

5. When I forcibly terminate the client, then server is reading the data and displaying.

This behaviour always occurs, which shows my implementation is wrong some where.

Message was edited by:

chaos_begins_here to give more information

chaos_begins_herea at 2007-7-8 2:03:37 > top of Java-index,Core,Core APIs...
# 7
readFrame() is closing the input stream, and therefore the socket, after reading one frame.
ejpa at 2007-7-8 2:03:37 > top of Java-index,Core,Core APIs...