Kushal Kushal - 5 months ago 8
Java Question

Opening read/write streams multiple times from a Socket

In a class where I have

ServerSocket
listening for incoming connections, following is the code:

while(isRunning)
{
try
{
Socket s = mysocketserver.accept();
acknowledgeClient(s);
new ClientHandler(s).start(); //Start new thread to serve the client, and get back to accept new connections.
}
catch(Exception ex)
{
ex.printStackTrace();
}
}


And following is
acknowledgeClient(Socket s)
code.

ObjectInputStream in = new ObjectInputStream(s.getInputStream);
ObjectOutputStream out = new ObjectOutputStream(s.getOutStream);
String msg = in.readObject().toString();
System.out.println(msg+" is Connected"); //Show who's connected
out.writeObject("success"); //Respond with success.
in.close();
out.close();


The
run()
method of the
ClientHandler
.

try
{
in = new ObjectInputStream(client.getInputStream());
out = new ObjectOutputstream(client.getOutputStream());
String msg = "";
while(!msg.equalsIgnoreCase("bye"))
{
msg = in.readObject().toString();
System.out.println("Client Says - "+msg);
out.writeObject("success");
}
in.close();
out.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}


And following is the way how client program communicates with this Echo Server.

try
{
int count = 10;
client = new Socket("localhost",8666);
in = new ObjectInputStream(client.getInputStream());
out = new ObjectOutputstream(client.getOutputStream());
out.writeObject("Foo");
System.out.println("Connection Status : "+in.readObject().toString());
while(count>0)
{
out.writeObject("Hello!");
String resp = in.readObject().toString(); //Getting EOFException here.
System.out.println("Sent with :"+resp);
count--;
Thread.sleep(1000);
}
out.close();
in.close();
client.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}


As you might have noticed that, after the client is acknowledged after connection, I close the read/write streams, and from new thread which is serving the client, I'm opening the stream again, and from the server reading/writing from the connected socket is started, but as soon as I attempt to read server's response on sending
Hello!
by client, it crashes with
EOFException
instead of getting
success
.

I know the causes for which EOF occurs but not getting the clue that why is it happening here, I'm not attempting to read socket that has nothing in its stream (it should have
success
as written by server).

Is it too early that client is attempting to read socket before server has printed
Hello!
on its end and written
success
as response?

P.S. : I know its not a good way to ask question by putting so much code, we're expected here to get answers of the issue and understand it rather than having our problem fixed by others and get away. So, I've provided this much code to show all aspects from the problem.

Answer

I studied the source code of ObjectInputStream, and it appears that the reference to the original input stream s.getInputStream() is stored inside the ObjectInputStream.

When you close the ObjectInputStream, s.getInputStream() is closed as well.

Once an input stream is closed, it cannot be opened again. Thus, you get an EOFException, which indicates that you are at the end of the stream (since the stream could not be opened again).

You should do something like this to acknowledge the client.

Inside the run() method of the ClientHandler:

try {
    // acknowledge client
    ObjectInputStream in = new ObjectInputStream(s.getInputStream());
    ObjectOutputStream out = new ObjectOutputStream(s.getOutStream());
    String msg = in.readObject().toString();
    System.out.println(msg+" is Connected"); //Show who's connected
    out.writeObject("success"); //Respond with success.
    // end acknowledge client

    String msg = "";
    while(!msg.equalsIgnoreCase("bye"))
    {
        msg = in.readObject().toString();
        System.out.println("Client Says - "+msg);
        out.writeObject("success");
    }
    in.close();
    out.close();
}
catch(Exception ex)
{
    ex.printStackTrace();
}

If you want to isolate the acknowledge code in a seperate method, just be sure to maintain a proper reference to the same ObjectInputStream without closing the stream, then pass the reference around.

Comments