Сокет Java, не выдающий исключения на неисправном сокете?

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

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

7
задан erotsppa 29 June 2010 в 22:42
поделиться

4 ответа

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

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

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

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

2
ответ дан 7 December 2019 в 16:38
поделиться

Ключевое слово здесь (без правильного закрытия сокета) .

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

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

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

Даже с этими мерами предосторожности вы должны указать время ожидания приложения, специфичное для вашего протокола.

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

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

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

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

1
ответ дан 7 December 2019 в 16:38
поделиться

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

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

Что касается второй части (не определяющей, когда вы пишете в этот сокет), это, вероятно, вопрос буфера и тайм-аута (как уже предлагали другие).

0
ответ дан 7 December 2019 в 16:38
поделиться

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

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

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

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

0
ответ дан 7 December 2019 в 16:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: