当 IntelliJ 断开客户端连接时,套接字输入流在 readLine 上连续返回 null

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

我有一个简单的 TCP 服务器:

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();
    }
  }
}

和一个客户

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"));
    }
  }
}

客户端发送用户键入的消息,服务器以 [​​=38=] 和时间戳响应。除了一种情况外,一切都很好。如果我使用 IntelliJ 关闭客户端,关闭然后 "Disconnect" 按钮

服务器readLine连续returnsnull并打印

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

解释了 IntelliJ disconnect 行为 here

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

因此,这意味着断开连接会保留进程 运行,但 IntelliJ 将不再附加到它。 这仍然不能解释为什么 readLine 不断返回 null.

谁能解释这种行为?

客户端已断开连接,因此客户端与服务器的连接已断开。但是你的代码没有处理那个。当连接断开时,即构成 "end of stream" 和 BufferedReaderreadLine 函数 returns null。这正是它在输出中告诉您的内容:

Received: null [...]

您需要检查 null return 值并跳出循环。

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

客户端和服务器都应该做那个测试。在真实的网络中,你永远不知道你的同伴什么时候会消失。

请参阅 https://docs.oracle.com/javase/8/docs/api/java/io/BufferedReader.html#readLine-- 处的文档(Returns: ... 如果已到达流末尾,则为 null)

(我不知道这里的 IntelliJ 到底发生了什么,但显然服务器线程仍然是 运行。服务器和客户端大概是 运行 在单独的子进程或线程中。 )