2010-12-28 4 views
0

Я пишу программу с использованием неблокирующего сокета Java и TCP. Я понимаю, что TCP - это протокол потока, но IP-протокол подслоя использует пакеты. Когда я вызываю SocketChannel.read (ByteBuffer dst), я всегда получаю весь контент IP-пакетов? или он может заканчиваться в любой позиции в середине пакета?Неблокирующий сокет с TCP

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

Изменить: предположим, что на стороне отправителя сообщения отправляются с большим интервалом (например, 1 секунда), поэтому они не собираются группироваться в одном IP-пакете. На стороне приемника буфер, используемый для вызова read (ByteBuffer dst), достаточно велик для хранения любого сообщения.

ответ

2

TCP - это поток байтов. Каждое чтение будет получать от 1 до максимального размера буфера, который вы предоставили, и количества байтов, доступных для чтения в это время.

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

Вы должны ВСЕГДА писать свой считываемый код таким образом, чтобы он мог обрабатывать кадрирование сообщений и собирать частичные сообщения или разделять несколько.

Вы можете обнаружить, что если вы не беспокоитесь об этой сложности, ваш код будет работать «большую часть времени», не полагайтесь на это. Как только вы работаете в оживленной сети или через Интернет, или как только вы увеличите размер своих сообщений, вы будете укушены своим сломанным кодом.

Я рассказываю о том, что TCP-сообщение обрамляет еще несколько здесь: http://www.serverframework.com/asynchronousevents/2010/10/message-framing-a-length-prefixed-packet-echo-server.html и здесь: http://www.serverframework.com/asynchronousevents/2010/10/more-complex-message-framing.html, хотя это с точки зрения реализации на C++, поэтому оно может или не может вас заинтересовать.

0

Из документации SocketChannel:

A socket channel in non-blocking mode, for example, cannot read 
any more bytes than are immediately available from the socket's input buffer; 

Так что, если ваш буфер назначения достаточно велик, вы должны быть в состоянии потреблять все данные в входном буфере сокета.

1

API сокетов не гарантирует, что вызовы send() и recv() коррелируют с дейтаграммами для сокетов TCP. На отправляющей стороне все может быть перегруппировано уже, например. система может отложить отправку одной дейтаграммы, чтобы узнать, имеет ли приложение больше данных; на принимающей стороне вызов чтения может извлекать данные из нескольких дейтаграмм или частичную датаграмму, если размер, указанный вызывающим абонентом, требует взлома пакета.

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