TCP keep-alive, чтобы определить, отключен ли клиент в netty

Я пытаюсь определить, закрыл ли клиент соединение сокета от netty. Есть ли способ сделать это?

Ответ 1

В обычном случае, когда клиент закрывает сокет через close() и завершение установления связи TCP завершено успешно, будет срабатывать событие channelInactive() (или channelClosed() в 3).

Однако в необычном случае, например, когда клиентская машина выходит из сети из-за сбоя питания или отсоединенного сетевого кабеля, это может занять много времени, пока вы не обнаружите, что соединение было фактически отключено. Чтобы обнаружить эту ситуацию, вам нужно периодически отправлять сообщение клиенту и ожидать получения ответа в течение определенного времени. Это как ping - вы должны определить периодическое сообщение ping и pong в своем протоколе, который практически ничего не делает, кроме проверки работоспособности соединения.

В качестве альтернативы вы можете включить SO_KEEPALIVE, но интервал keepalive этого параметра обычно зависит от ОС, и я бы не рекомендовал его использовать.

Чтобы помочь пользователю реализовать подобное поведение относительно легко, Netty предоставляет ReadTimeoutHandler. Настройте свой конвейер так, чтобы ReadTimeoutHandler вызывал исключение, когда нет входящего трафика в течение определенного времени, и закрывайте соединение в исключении в методе обработчика exceptionCaught(). Если вы являетесь участником, который должен отправлять периодическое сообщение ping, используйте таймер (или IdleStateHandler) для его отправки.

Ответ 2

Это зависит от вашего протокола, который вы используете ontop netty. Если вы создадите его для поддержки сообщений, подобных ping, вы можете просто отправить эти сообщения. Кроме того, netty - всего лишь довольно тонкая оболочка вокруг TCP.

Также см. этот SO-сообщение, в котором описывается isOpen() и связанный. Это, однако, не решает проблему keep-alive.

Ответ 3

Если вы пишете сервер, а netty - ваш клиент, ваш сервер может обнаружить отключение, вызвав select() или эквивалент, чтобы определить, когда сокет будет читаемым, а затем вызовите recv(). Если recv() возвращает 0, то сокет был закрыт изящно клиентом. Если recv() возвращает -1, то отметьте errno или эквивалент для фактической ошибки (за небольшим исключением, большинство ошибок следует рассматривать как несравнимое отключение). Дело в неожиданных разъединениях заключается в том, что они могут занять много времени для обнаружения ОС, поэтому вам придется либо включить поддержку TCP-авитов, либо потребовать от клиента отправки данных на сервер на регулярной основе. Если ничего не получено от клиента в течение определенного периода времени, просто предположите, что клиент ушел и закрыл конец вашего соединения. Если клиент хочет, он может снова подключиться.

Ответ 4

Если вы прочитали из соединения, которое было закрыто одноранговым узлом, вы получите указание конца потока в зависимости от API. Если вы пишете на такое соединение, вы получите IOException: "connection reset". TCP не предоставляет другого способа обнаружения закрытого соединения.

TCP keep-alive (a) отключен по умолчанию и (b) работает только каждые два часа по умолчанию при включении. Это, вероятно, не то, что вы хотите. Если вы используете его, и вы читаете или записываете после того, как обнаружили, что соединение нарушено, вы получите ошибку reset выше,