Mike D.
Mike D.

Reputation: 11

Disconnecting a socket to server

I am trying to test my chat client application by creating a socket and connecting it to the server, sending a message and closing the socket (via the server's close method). However, it seems that when I close the socket the client thread still awaits for client input. However, I have put if clause to stop it from waiting. Here is my test:

   @Test
    public void testMessagesReceived() throws IOException
 {  
    ServerSocket s = server.getSocket();
    System.out.println(s);  
    mysocket = new Socket("127.0.0.1", 3000);

    final PrintWriter stream = new PrintWriter(mysocket.getOutputStream(), true);

    stream.println("Default room");

}
    @AfterSuite
public void stopServer() {
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {  
        e.printStackTrace();
    }
    server.stop();
}

However, when the server.stop() executes and closes the socket I get an exception in the client thread which is alive and uses this socket, here:

 public void acceptFromConsole() throws IOException {

    if (!socket.isClosed()) {


    final BufferedReader fromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));

    String message;
    while ((message = fromClient.readLine()) != null) { // Exception here
    if (message.contains(TelnetUtilities.Quit.toString())) {
        room.removeClient(id);
        break;
    }   
}

Here is the full stacktrace:

   java.net.SocketException: Socket closed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
at sun.nio.cs.StreamDecoder.read(Unknown Source)
at java.io.InputStreamReader.read(Unknown Source)
at java.io.BufferedReader.fill(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at java.io.BufferedReader.readLine(Unknown Source)
at com.egt.chat.server.ClientContainer.acceptFromConsole(ClientContainer.java:40)
at com.egt.chat.server.ClientContainerRunnable.run(ClientContainerRunnable.java:28)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

It seems to me that in one thread I close the socket ,however the client thread doesn't see the change on the socket and that check if(!socket.isClosed()) returns true and the flow of execution continues and while I try to read it of course throws exception that I am trying to read from a closed socket ,is there a way to overcome this?

Upvotes: 0

Views: 331

Answers (1)

Robert
Robert

Reputation: 42774

Your code is working as it should be. When you forcefully disconnect the socket your code is the while loop:

  while ((message = fromClient.readLine()) != null) { // Exception here
      if (message.contains(TelnetUtilities.Quit.toString())) {
          room.removeClient(id);
          break;
      }

readLine() is waiting for incoming data. If you would not close the connection it would wait forever for new data. Then you close the connection and readLine() (or better the underlaying socketRead method) now recognizes that it can't read data from a closed socket and raises the exception.

Therefore this exception is an expected exception at this point. Catch it and be happy.

I would do it this way: Add a boolean variable like stopServerCalled which is by default false and is set to true when stopServer() is called.

try {
    while ((message = fromClient.readLine()) != null) { // Exception here
        if (message.contains(TelnetUtilities.Quit.toString())) {
            room.removeClient(id);
            break;
        }
} catch (SocketException e) {
    // check if this is an expected exception and if yes ignore it
    if (!stopServerCalled) 
        throw e;
}

Upvotes: 1

Related Questions