неблокирующее программирование сокета udp в C: что я получу? - PullRequest
8 голосов
/ 10 февраля 2010

У меня проблема с пониманием того, что recv () / recvfrom () возвращает из неблокирующего UDP-сокета.

Немного конкретнее и по сравнению с TCP (поправьте меня, если я не прав):

  • Блокирующий сокет (TCP или UDP) не будет возвращаться из recv (), пока в буфере не будет данных. Это может быть некоторое количество байтов (TCP) или полная дейтаграмма (UDP).

  • Неблокирующий сокет TCP возвращает либо EWOULDBLOCK (linux) / WSAEWOULDBLOCK (windows), либо байты, которые в данный момент находятся в буфере. Поскольку данные TCP являются потоком, не имеет значения, сколько байтов будет возвращено.

Теперь вопрос:

  • Неблокирующий сокет UDP также возвращает WOULDBLOCK (linux) / WSAEWOULDBLOCK (windows), если нет доступных данных. Но если данные доступны, неблокирующий сокет UDP возвращает только несколько байтов, что может означать, что вы получаете только половину дейтаграммы ИЛИ UDP-сокет всегда возвращает полные дейтаграммы ??

Edit:

Что я имею в виду под «половиной дейтаграммы»: что произойдет, если я вызову recv () как раз в тот момент, когда сокет в данный момент получает дейтаграмму. В этот момент в буфере есть несколько байтов, но датаграмма еще не завершена.

Ваши объяснения и комментарии приветствуются. Спасибо!

Ответы [ 3 ]

8 голосов
/ 11 февраля 2010

Наконец, оправдание, чтобы выкопать мои книги Стивенса из моих старых офисных коробок.

Если буфер достаточно большой, стандартные функции сокетов recv() и recvfrom() Беркли никогда не будут возвращать частичную дейтаграмму. Дейтаграмма не доступна приложению, пока ядро ​​полностью не получит и не соберет дейтаграмму.

Интересно, что сегодня это не так уж много (вообще?), Другие сетевые программные интерфейсы не согласны с поведением, когда предоставленный буфер слишком мал:

Традиционная версия сокетов API в Беркли обрезает дейтаграмму, отбрасывая лишние данные. Будет ли приложение уведомлено, зависит от версии. (4.3BSD Reno и более поздние версии могут уведомить приложение о том, что датаграмма была усечена.)

API сокетов в SVR4 (включая Solaris 2.x) не усекает дейтаграмму. Любые лишние данные возвращаются в последующих чтениях. Приложение не уведомлено о том, что из одной дейтаграммы UDP выполняется несколько операций чтения.

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

(Стивенс, иллюстрированный TCP / IP, том 1, стр. 160)

1 голос
/ 10 февраля 2010

Да, UDP просто возвращает данные, которые были переданы в этой одной дейтаграмме. UDP не ориентирован на поток, как TCP. Дейтаграммы являются дискретными передачами и на самом деле никак не связаны с другими дейтаграммами. Вот почему опция сокета для TCP - SOCK_STREAM.

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

0 голосов
/ 10 февраля 2010

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

Редактировать: Я уверен, что вы не можете получить половину дейтаграммы. Либо датаграмма поступила в буфер, либо нет.

...