Чтобы отправлять дискретные сообщения по протоколу потока байтов, вы должны кодировать сообщения на каком-то языке кадрирования. Сеть может нарезать протокол на пакеты произвольного размера, поэтому полученные сообщения никак не соотносятся с вашими сообщениями. Получатель должен реализовать конечный автомат, который распознает кадры.
Простой протокол кадрирования должен иметь некоторое поле длины (скажем, два октета: 16 бит, максимальная длина кадра 65535 байт). За полем длины следует ровно столько байтов.
Вы даже не должны предполагать, что само поле длины получено сразу. Вы можете запросить два байта, но recv
может вернуть только один. Этого не произойдет для самого первого сообщения, полученного из сокета, потому что сегменты сети (или локального IPC-канала, если уж на то пошло) никогда не бывают длиной всего в один байт. Но где-то в середине потока первый байт 16-битного поля может оказаться на последней позиции одного сетевого кадра.
Простой способ справиться с этим — использовать буферизованную библиотеку ввода-вывода вместо необработанных файловых дескрипторов операционной системы. В среде POSIX вы можете взять дескриптор открытого сокета и использовать функцию fdopen
, чтобы связать его с потоком FILE *
. Затем вы можете использовать такие функции, как getc
и fread
, чтобы упростить обработку ввода (несколько).
Если внутриполосное кадрирование неприемлемо, вам следует использовать протокол, который поддерживает кадрирование, а именно сокеты типа дейтаграммы. Основным недостатком этого является то, что основным протоколом на основе дейтаграмм, используемым через IP, является UDP, а UDP ненадежен. Это усложняет ваше приложение для работы с неупорядоченными и отсутствующими кадрами. Размер фреймов также ограничен максимальным размером дейтаграммы IP, который составляет около 64 килобайт, включая все заголовки протокола.
Большие дейтаграммы UDP фрагментируются, что при ненадежности сети приводит к еще большей ненадежности: если какой-либо IP-фрагмент потерян, весь пакет теряется. Все это должно быть ретранслировано; нет возможности просто получить повторение утраченного фрагмента. Протокол TCP выполняет «обнаружение MTU пути», чтобы настроить размер своего сегмента, чтобы избежать фрагментации IP, и TCP имеет выборочную повторную передачу для восстановления отсутствующих сегментов.
person
Kaz
schedule
07.06.2013
recv
не знает, какой размер порции данных! Вы можете сделать размер буфера равным толькоlength
. - person Eddy_Em   schedule 07.06.2013