【问题标题】:Interrupt server thread when client closes TCP connection客户端关闭 TCP 连接时中断服务器线程
【发布时间】:2023-03-23 11:18:01
【问题描述】:

我有一个 Java 中的多线程 TCP 服务器,它允许来自多个客户端的连接,并为每个连接的客户端启动一个新的 ServerThread:

服务器类:

while (!Thread.currentThread().isInterrupted()) {
    try {
        // Create a new thread for each incoming connection.
        Socket clientSocket = serverSocket.accept();
        ServerThread serverThread = new ServerThread(clientSocket, this);
        serverThread.run();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

在特定超时后,客户端关闭其套接字。如何中断与客户端连接的 ServerThread? clientsocket.isClosed()!clientSocket.isConnected() 由于某种原因无法正常工作。

最后,我用下面的 sn-ps 得到了它(解决方案是资源块中的套接字和无穷无尽的in.readLine() == null):

服务器类

public void run() {
    while (!Thread.currentThread().isInterrupted()) {
        try {
            // Create a new thread for each incoming connection.
            Socket clientSocket = serverSocket.accept();
            ServerThread serverThread = new ServerThread(clientSocket, this);
            serverThread.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ServerThread 类:

public void run() {
    try (Socket socket = clientSocket; // Enable auto-close for socket...
         PrintWriter out = ...; BufferedReader in = ...;) {

        ...

        while (!clientSocket.isClosed() && !isInterrupted()) {
            if (in.readLine() == null) {
                break;
            }
        }
        System.err.println("Client with port " + clientSocket.getPort() + " closed connection to server.");
    } catch (IOException e) {
        e.printStackTrace();
    }
}

客户端类:我使用与 ServerThread 类中相同的资源块尝试

【问题讨论】:

  • 1.您根本没有多线程服务器。你应该打电话给serverThread.start(),而不是serverThread.run()。目前,您根本没有创建任何真正的线程。 2. isClosed()isConnected() 方法告诉你你的套接字的状态,而不是连接的状态。当对等方断开连接时,它们不会神奇地变为假。 3.不需要中断ServerThread。在这种情况下,从套接字读取会返回流的结尾:你在测试吗?
  • 但是如果我不中断ServerThread,过一段时间就会有大量的ServerThreads。
  • 线程本身在读取时识别流结束,或在写入时识别 IOExceptions,或读取超时,并关闭其套接字并退出。这就是所有 Java 阻塞模式服务器的工作方式。您需要阅读 Java 教程的自定义网络部分。

标签: java multithreading sockets tcp server


【解决方案1】:

如果客户端在没有发送明确的 FIN 的情况下不干净地关闭 TCP 套接字(例如,如果客户端崩溃),那么服务器将不会知道它,直到它下一次尝试向客户端发送数据包(此时客户端将发送一个 RST 数据包告诉服务器套接字已关闭)。

假设您同时控制客户端和服务器代码,检查连接的最可靠方法是在两者之间实现心跳机制,以便它们定期在它们之间 ping 一小段数据以检查连接的有效性.

【讨论】:

  • 谢谢,你能解释一下在关闭连接之前如何从客户端发送FIN吗?
  • 您使用的是标准 Java 吗?当你调用 socket.close() 我相信它应该发送一个 FIN。不过,您需要使用 Wireshark 之类的工具来查看幕后情况。
  • 是的,我使用标准 Java。我需要调用特定的方法来接收来自客户端的 FIN 吗?
  • 你的意思是我应该尝试打开一个 InputStream 吗?
  • @jannnik 当然你应该打开一个输入流。服务器如何知道客户端想要什么?
【解决方案2】:

保持活动套接字选项是监视持久 TCP 连接的标准方法。 如果您的服务器在中止期间处于阻塞读取操作中,您将收到 java.io.IOException: read failed。在异步情况下,您将收到带有 -1 的读取密钥。 在写入状态下,您将得到: 对等方重置连接:套接字写入错误。 如果连接不可恢复,只需处理异常或错误代码即可关闭线程。

【讨论】:

  • 他在问如何检测客户端何时关闭套接字,这个没有回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-06
  • 2021-08-12
  • 1970-01-01
  • 2014-03-04
  • 1970-01-01
相关资源
最近更新 更多