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
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?
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.)