作为对最近一个问题的回应,我想知道为什么在Java中如果不尝试在TCP套接字上进行读/写操作就无法检测到套接字已被对等端正常关闭了,这是为什么?不管是使用pre-NIO Socket
还是NIO,似乎都是这种情况SocketChannel
。
当对等方正常关闭TCP连接时,连接两端的TCP堆栈都会知道这一事实。服务器端(启动关闭操作的服务器)以状态结束FIN_WAIT2
,而客户端端(未明确响应关闭操作的服务器)以状态服务器结束CLOSE_WAIT
。为什么没有一个方法Socket
或SocketChannel
可以查询TCP堆栈看到底层的TCP连接是否已经终止?TCP堆栈不提供此类状态信息吗?还是为了避免昂贵地调用内核而做出的设计决定?
在已经发布了该问题的一些答案的用户的帮助下,我认为我知道问题可能来自何处。没有显式关闭连接的那一侧将以TCP状态结束,CLOSE_WAIT
这意味着该连接正在关闭过程中,并等待该一侧发出自己的CLOSE
操作。我想这是公平的,以至于isConnected
收益true
和isClosed
回报false
,但为什么没有像isClosing
?
以下是使用pre-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
...
Socket.close
不是一个优雅的关闭。