最近の質問のフォローアップとして、Javaでは、TCPソケットで読み取り/書き込みを試行せずに、ソケットがピアによって正常に閉じられたことを検出できないのはなぜでしょうか。Socket
これは、pre-NIOとNIOのどちらを使用するかに関係なく当てはまるようSocketChannel
です。
ピアがTCP接続を正常に閉じると、接続の両側のTCPスタックがその事実を認識します。サーバー側(シャットダウンを開始する側)は状態FIN_WAIT2
になり、クライアント側(シャットダウンに明示的に応答しない側)は状態になりCLOSE_WAIT
ます。基盤となるTCP接続が終了したかどうかを確認するためにTCPスタックにクエリを実行できるSocket
メソッドがないのはなぜですか?SocketChannel
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
...