Как следствие недавнего вопроса , интересно, почему это невозможно в 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
?
Ниже приведены тестовые классы, в которых используются сокеты 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
...