Сокет Java не выбрасывает исключения на мертвый сокет? - PullRequest
7 голосов
/ 30 июня 2010

У нас есть простая клиент-серверная архитектура между нашим мобильным устройством и нашим сервером, написанная на Java.Чрезвычайно простая реализация ServerSocket и Socket.Однако одна проблема заключается в том, что когда клиент завершает работу внезапно (без надлежащего закрытия сокета), сервер не знает, что он отключен.Кроме того, сервер может продолжать запись в этот сокет без каких-либо исключений.Зачем?

Согласно документации, сокеты Java должны выдавать исключения, если вы пытаетесь записать в сокет, который недоступен на другом конце!

Ответы [ 5 ]

2 голосов
/ 30 июня 2010

Время ожидания истекает через время ожидания повторной передачи (RTO).Однако RTO рассчитывается с использованием сложного алгоритма, основанного на латентности сети (RTT), см. Этот RFC,

http://www.ietf.org/rfc/rfc2988.txt

Таким образом, в мобильной сети это может занять минуты.Подождите 10 минут, чтобы узнать, сможете ли вы получить тайм-аут.

Решение этой проблемы заключается в добавлении сердцебиения в собственный протокол приложения и разрыве соединения, когда вы не получаете ACK длясердцебиение.

1 голос
/ 30 июня 2010

Ключевое слово здесь (without closing the socket properly).

Сокеты всегда следует приобретать и утилизировать следующим образом:

final Socket socket = ...; // connect code

try
{
    use( socket ); // use socket
}
finally
{
    socket.close( ); // dispose
}

Даже с учетом этих мер предосторожности вы должны указать тайм-ауты приложения, относящиеся кваш протокол.

Мой опыт показал, что, к сожалению, вы не можете надежно использовать любую из функций тайм-аута Socket (например, нет времени ожидания для операций записи, и даже операции чтения могут иногда зависать).

Вот почему вам нужен сторожевой поток, который устанавливает таймауты вашего приложения и удаляет сокеты, которые некоторое время не отвечали.

Один удобный способ сделать это - инициализировать Socket и ServerSocket через соответствующие каналы в Java..nio.Основное преимущество таких сокетов состоит в том, что они являются прерываемыми, поэтому вы можете просто прервать поток, выполняющий протокол сокетов, и убедиться, что сокет правильно отключен.

Обратите внимание, что вы должны принудительно устанавливать таймауты приложений с обеих сторон., поскольку это только вопрос времени и неудачи, когда вы можете столкнуться с невосприимчивыми сокетами.

0 голосов
/ 02 сентября 2010

Я столкнулся с той же проблемой. Я думаю, что когда вы регистрируете сокет с помощью селектора, он не выдает никаких исключений. Вы используете селектор со своим сокетом?

0 голосов
/ 30 июня 2010

Чтобы ответить на первую часть вопроса (о незнании того, что клиент внезапно отключился), в TCP вы не сможете узнать, завершилось ли соединение, пока не попытаетесь его использовать.

Понятие гарантированной доставки в TCP довольно тонкое: на самом деле доставка не гарантируется приложению на другом конце (это зависит от того, что на самом деле означает гарантированная). Раздел 2.6 RFC 793 (TCP) дает более подробную информацию по этой теме. Этот поток в списке обсуждений Restlet и этот поток в списке ядра Linux также может представлять интерес.

Для второй части (не обнаруживается при записик этому сокету), это, вероятно, вопрос о буфере и времени ожидания (как уже предлагали другие).

0 голосов
/ 30 июня 2010

TCP / IP связь может быть очень странной. TCP будет некоторое время повторять попытки на нижних уровнях стека, даже не сообщая верхним уровням, что что-то произошло.

Я бы полностью ожидал, что через некоторое время (от 30 секунд до нескольких минут) вы увидите ошибку, но я не проверял это, я просто ухожу, как обычно работают приложения TCP.

Возможно, вам удастся ужесточить спецификации TCP (повтор, тайм-аут и т. Д.), Но, опять же, вы не сильно с этим справились.

Кроме того, возможно, я совершенно не прав, и реализация Java, которую вы используете, просто ненадежна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...