Search code examples
javasocketsintellij-ideaserversocket

Socket input stream continuously returning null on readLine when Client disconnected by IntelliJ


I have a simple TCP server:

public class ServerSocketRunner {

  public static void main(String[] args) throws Exception {
    ServerSocket serverSocket = new ServerSocket(9000);

    while (true) {
      Socket socket = serverSocket.accept();

      new Thread(() -> {
        System.out.println("New client connected");
        try (PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));) {

          String inputLine, outputLine;
          do {
            inputLine = in.readLine();
            System.out.print("Received: " + inputLine);
            String serverResponse = "Message Received: " + now();
            System.out.println("Sending: " + serverResponse);
            out.println(serverResponse);
          } while (!"bye".equals(inputLine));

          socket.close();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }).start();
    }
  }
}

and a client

public class ClientRunner {

  public static void main(String[] args) throws Exception {
    try (Socket socket = new Socket("localhost", 9000);
        Scanner input = new Scanner(socket.getInputStream());
        PrintWriter output = new PrintWriter(socket.getOutputStream(), true)) {

      Scanner userEntry = new Scanner(System.in);
      String message, response;
      do {
        System.out.print("Enter message: ");
        message = userEntry.nextLine();
        output.println(message);
        response = input.nextLine();
        System.out.println("\nSERVER> " + response);
      } while (!message.equals("bye"));
    }
  }
}

The client sends messages which user types, server responds with "Message received" and a timestamp. All works nicely, except for one scenario. If I close the client using IntelliJ, close and then "Disconnect" button

enter image description here

the server readLine continuously returns null and prints

Received: nullSending: Message Received: 2019-10-03T14:44:36.962
Received: nullSending: Message Received: 2019-10-03T14:44:36.962
Received: nullSending: Message Received: 2019-10-03T14:44:36.962
...

The IntelliJ disconnect behavior is explained here

Disconnect (if available) ---> If this option is selected, the running process is disconnected.

So, this would mean that the disconnect keeps the process running, but the IntelliJ will no more be attached to it. Still this does not explain why readLine is continuously returning null.

Anyone can explain this behavior?


Solution

  • The client has been disconnected, and so the connection between client and server has been broken. But your code isn't handling that. When the connection is broken, that constitutes "end of stream" and the BufferedReader's readLine function returns null. And that's exactly what it's telling you in the output:

    Received: null [...]
    

    You need to check for the null return value and break out of your loop.

        inputLine = in.readLine();
        if (inputLine == null) {
            System.out.print("Client disconnected. Leaving\n");
            break;
        }
    

    Both client and server should do that test. In a real network, you never know when your peer is going to vanish.

    See documentation at https://docs.oracle.com/javase/8/docs/api/java/io/BufferedReader.html#readLine-- (Returns: ... or null if the end of the stream has been reached)

    (I don't know exactly what's going on in IntelliJ here, but obviously the server thread is still running. Server and client presumably are running in separate sub-processes or threads.)