作为 最近的问题的后续,我想知道为什么在 Java 中,如果不尝试在 TCP 套接字上读/写,就不可能检测到该套接字已被对等端优雅地关闭?无论使用前 NIO Socket
还是 NIO SocketChannel
,情况似乎都是如此。
当一个节点优雅地关闭一个 TCP 连接时,连接两端的 TCP 堆栈都知道这个事实。服务器端(启动关闭的端)最终处于状态 FIN_WAIT2
,而客户端(不显式响应关闭的端)最终处于状态 CLOSE_WAIT
。为什么在 Socket
或 SocketChannel
中没有一个方法可以查询 TCP 堆栈来查看底层 TCP 连接是否已经终止?是因为 TCP 协议栈没有提供这样的状态信息吗?还是为了避免对内核进行昂贵的调用而做出的设计决定?
在已经发布了这个问题的一些答案的用户的帮助下,我想我知道这个问题可能是从哪里来的了。没有显式关闭连接的一端最终处于 TCP 状态 CLOSE_WAIT
,这意味着连接正处于关闭过程中,并等待该端发出自己的 CLOSE
操作。我认为 isConnected
返回 true
和 isClosed
返回 false
是很公平的,但是为什么没有类似于 isClosing
的东西呢?
下面是使用前 NIO 套接字的测试类,但是使用 NIO 可以获得相同的结果。
import java.net.ServerSocket;
import java.net.Socket;
public class MyServer {
public static void main(String[] args) throws Exception {
final ServerSocket ss = new ServerSocket(12345);
final Socket cs = ss.accept();
System.out.println("Accepted connection");
Thread.sleep(5000);
cs.close();
System.out.println("Closed connection");
ss.close();
Thread.sleep(100000);
}
}
import java.net.Socket;
public class MyClient {
public static void main(String[] args) throws Exception {
final Socket s = new Socket("localhost", 12345);
for (int i = 0; i < 10; i++) {
System.out.println("connected: " + s.isConnected() +
", closed: " + s.isClosed());
Thread.sleep(1000);
}
Thread.sleep(100000);
}
}
当测试客户端连接到测试服务器时,即使在服务器启动连接关闭之后,输出仍然保持不变:
connected: true, closed: false
connected: true, closed: false
...