Я пытаюсь определить, закрыл ли клиент соединение сокета от netty. Есть ли способ сделать это?
TCP keep-alive, чтобы определить, отключен ли клиент в 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 выше,