2010-10-29 2 views
2

Я использую TCP Socket в своем приложении Java. Я пытаюсь получить данные байт с некоторого устройства с помощью метода readInt().TCP Socket Hangs при получении в Java

Этот метод работает нормально, если я получаю 4 байта от устройства. Но если я получаю меньше 4 байтов или ничего, то зависает readInt(). Он заблокирован и не возвращается. Он должен выбросить исключение EOFException, если нет данных для получения, но он висит.

Код:

DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream()); 
DataInputStream din = new DataInputStream(socket.getInputStream()); 

int res = din.readInt(); 

ответ

4

EOFException не бросят, пока сокет закрывается.

Этот метод должен содержать, когда вы пытаетесь прочитать больше данных, чем доступно. Он возвращает EOFException только тогда, когда сокет закрывается, так как это фактическое условие EOF. Если сокет остается открытым, он блокируется, пока на нем не будет достаточно данных для заполнения запроса.

Это часть фундаментальной природы работы сокетов. Для того, чтобы Java вела себя по-другому, ему пришлось бы неправильно выполнять поведение сокетов.

При составлении протокола сокетов вы должны это учитывать. Почему вы ожидаете получения int и отправляется только часть int? Этого никогда не должно быть. Если вы хотите отправлять разные типы данных, сначала нужно указать какой-то байт заголовка, чтобы сообщить получателю, какие данные идут дальше, чтобы он знал, как обрабатывать его и что с ним делать.

+0

Правда, блокирование - это естественное поведение. –

1

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

0

Классы, которые вы используете, составляют часть пакета java.io, который выполняет блокировки I/O. Правильным решением является переход на использование неблокирующих классов ввода-вывода, определенных в java.nio. Будьте предупреждены, что писать неблокирующее приложение ввода-вывода нетривиально. Тем не менее, это единственное решение, позволяющее избежать потенциального блокирования потока ввода-вывода неограниченно.

Обратите внимание, что в качестве взломанного решения вы можете использовать выделенный поток блокировки ввода-вывода, который просто считывает и добавляет байты в BlockingQueue, опрошенных другим потоком. Потребительский поток мог бы позвонить poll(long, TimeUnit) на BlockingQueue с достаточно длинным таймаутом, и если вызванный звонок null может означать, что больше данных не было. Обратите внимание, что это довольно уродливое решение, так как это означает, что поток «производитель» ввода-вывода останется заблокированным на этом этапе.

+0

Нет, правильное решение - не пытаться читать 4-байтовое целое число, когда устройство не отправляет его. – EJP

+0

@EJP: Это ставит ваше приложение на милость устройства; Если с устройством обнаружена ошибка или она просто отключена/недоступна (оставив висящий TCP-сокет), поток приложений будет блокироваться неограниченно долго. Следовательно, использование блокировки ввода-вывода не является изящным решением. – Adamski

+0

Это совершенно неверно. Просто установите тайм-аут чтения. Затем приложение будет блокировать только длину таймаута, а затем выбросить исключение SocketTimeoutException. В этой ситуации ничего нет, что делает java.nio «правильным решением». Это один из многих. – EJP

0

Эта ситуация может возникнуть только в случае неверного применения вашего протокола приложения. Почему вы ожидаете 4-байтовое целое число, и приложение отправляет только 1-3 байта? Действительно ли это отправка двоичного int? или вы, возможно, читаете и разбираете строку ASCII?

Смежные вопросы