сокет Java / поток вывода пишет: они блокируют? - PullRequest
35 голосов
/ 27 августа 2009

Если я ПИСУЮ только сокет в выходном потоке, он когда-нибудь заблокируется? Только чтение может заблокировать, верно? Кто-то сказал мне, что запись может блокировать, но я вижу только функцию времени ожидания для метода чтения сокета - Socket.setSoTimeout().

Мне не имеет смысла блокировать запись.

Ответы [ 2 ]

48 голосов
/ 27 августа 2009

Запись на Socket также может блокироваться, особенно если это TCP-сокет. ОС будет буферизовать только определенное количество непереданных (или переданных, но неподтвержденных) данных. Если вы пишете вещи быстрее, чем удаленное приложение может их прочитать, сокет в конечном итоге создаст резервную копию, и ваши write вызовы будут заблокированы.

Ответы на следующие вопросы:

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

Нет механизма для установки таймаута записи на java.net.Socket. Существует метод Socket.setSoTimeout(), но он влияет на вызовы accept() и read() ... а не на вызовы write(). Очевидно, вы можете получить тайм-ауты на запись, если используете NIO, неблокирующий режим и селектор, но это не так полезно, как вы можете себе представить.

Правильно реализованный стек TCP не удаляет буферизованные данные, если соединение не закрыто. Однако, когда вы получаете тайм-аут записи, неясно, были ли данные, которые в настоящее время находятся в буферах уровня ОС, получены другим концом ... или нет. Другая проблема заключается в том, что вы не знаете, сколько данных из вашего последнего write было фактически передано в буферы стека TCP уровня ОС. В отсутствие какого-либо протокола прикладного уровня для повторной синхронизации потока * единственная безопасная вещь, которую нужно сделать после тайм-аута на write, - это отключить соединение.

В отличие от этого, если вы используете сокет UDP, вызовы write() не будут блокироваться в течение значительного промежутка времени. Но недостатком является то, что если есть проблемы с сетью или удаленное приложение не работает, сообщения будут сброшены на пол без уведомления ни с одной стороны. Кроме того, вы можете обнаружить, что сообщения иногда доставляются удаленному приложению не по порядку. Вы, разработчик), должны решить эти проблемы.

* Теоретически это возможно сделать, но для большинства приложений нет смысла реализовывать дополнительный механизм повторной синхронизации поверх уже надежного (до некоторой степени) потока TCP / IP. И если бы это имело смысл, вам также пришлось бы иметь дело с возможностью того, что соединение закрылось ... так что было бы проще предположить , что оно закрыто.

7 голосов
/ 15 июля 2011

Единственный способ сделать это - использовать NIO и селекторы.

См. Статью инженера Sun / Oracle в этом отчете об ошибке: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4031100

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