В ответ на недавний вопрос я Интересно, почему в 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
?
Ниже приведены тестовые классы, в которых используются сокеты до 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
- не изящное завершение. - person user253751   schedule 10.05.2014