Java: 如何使用 ServerSocket 和 Socket 正确关闭套接字连接

Java: How to properly close a socket connection using ServerSocket and Socket

我目前有一个简单的即时消息程序,它利用了 Java 的 Socket and ServerSocket 类。它按预期运行,但是当我尝试关闭连接时,它没有使用 4 次握手 TCP 拆卸来关闭连接。相反,它使用 RST 数据包突然关闭连接。

我关闭连接的方式是从客户端向服务器发送一个字符串,服务器会将其识别为关闭连接的命令。然后,我在服务器上使用 ServerSocket.close() 方法,在客户端上使用 Socket.close() 方法。

使用这些 类 正确关闭 TCP 连接的正确方法 and/or 事件顺序是什么?

客户端断开代码:

//Disconnects from remote server
//Returns true on success, false on failure
public boolean disconnect(){
    try{
        this.clientOut.println("0x000000");
        this.clientRemoteSocket.close();
        this.isConnected = false;
        return true;
    }catch(Exception e){
        return false;
    }
}

服务器端断开代码:

//Check to see if the client wants to close the connection
//If yes, then close the connection and break out of the while loop
if(incoming.equals("0x000000")){
    serverLocalSocket.close();
    break;
}

编辑: 代码工作得很好。我只是想在 Java 中学习套接字编程,并且知道正确的 TCP 拆卸过程是包括 4 次握手。一个 FIN 数据包到远程主机,然后一个 ACK​​ 数据包从远程主机返回。然后是来自远程主机的 FIN 数据包,然后是到远程主机的 ACK 数据包。通过 Wireshark 监控流量时,我没有得到。相反,我正在获取远程服务器的 FIN,然后从服务器返回 RST/ACK。

image 描述了正确的 TCP 4 路拆卸过程。

到目前为止,我发现的所有内容都表明,所有需要的只是调用 close() 或让 Java 的 Try-with-resources 语句处理清理。我看不到 Java 实现了不符合标准 TCP 规范的功能。很有可能我以错误的顺序或类似的方式调用了某些行,我只是没有意识到。

关于 TCP 的重要部分是,如果您关闭套接字,您的合作伙伴会自动知道并在读取时抛出错误。

所以您在客户端中要做的就是:

clientRemoteSocket.close();

对于服务器,只需在正常读取数据时添加一个错误案例即可:

try {
    // Read from the socket:
    incoming = socketInputStream.read();

    // Handle the data here

} catch (IOException e) {
    // Client has disconnected
}

您可能会发现一个更具体的异常,我不确定,已经有一段时间了。但这应该有效。祝你好运!

如果您在关闭时重置自己的连接,可以:

  1. 您尚未读取对等方发送的所有待处理传入数据,或者
  2. 您已经写入了之前已被对方关闭的连接。

在这两种情况下,应用程序协议错误。