Может ли boost :: asio получать только полные UDP-дейтаграммы? - PullRequest
9 голосов
/ 23 марта 2010

Я работаю на UDP-сервере, созданном с boost :: asio, и я начал с учебника , настроенного под мои нужды. Когда я вызываю socket.receive_from(boost::asio::buffer(buf), remote, 0, error);, он заполняет мой буфер данными из пакета, но, если я правильно понимаю, он удаляет все данные, которые не помещаются в буфер. Последующие вызовы receive_from получат следующую доступную дейтаграмму, поэтому мне кажется, что произошла некоторая потеря данных даже без уведомления. Я неправильно это понимаю?

Я пытался многократно читать документацию boost :: asio, но мне не удалось найти подсказки о том, как я должен делать это правильно. Я хотел бы прочитать определенное количество данных, чтобы я мог их обработать; если чтение всей дейтаграммы - единственный способ, я могу справиться с этим, но тогда как я могу быть уверен, что не потеряю данные, которые получаю? Какой размер буфера я должен использовать, чтобы быть уверенным? Можно ли сказать, что мой буфер слишком мал и я теряю информацию?

Я должен предположить, что я, возможно, получаю огромные дейтаграммы.

Ответы [ 3 ]

9 голосов
/ 23 марта 2010

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

Например, протокол SNMP указывает, что:

Реализация этого протокола не должна принимать сообщения, длина которых превышает 484 октета. Тем не менее, рекомендуется, чтобы реализации поддерживали большие дейтаграммы, когда это возможно.

Вкратце: при разработке протокола связи вы должны учитывать, что дейтаграммы могут быть потеряны или обрезаны до определенного размера.

3 голосов
/ 24 августа 2012

Для IPv4 поле размера дейтаграммы в заголовке UDP составляет 16 бит, что дает максимальный размер 65 535 байт; когда вы вычитаете 8 байтов для заголовка, вы получите максимум 65 527 байтов данных. (Обратите внимание, что для этого потребуется фрагментация вмещающей дейтаграммы IPv4 независимо от базового MTU интерфейса из-за 16-битного поля длины пакета / фрагмента IPv4.)

Я просто использую буфер 64 КиБ, потому что это хорошее круглое число.

Вы должны иметь в виду, что на передающей стороне может потребоваться явное включение фрагментации, если вы хотите отправлять дейтаграммы больше, чем умещается в MTU интерфейса. С моей страницы Ubuntu 12.04 UDP (7):

   By default, Linux UDP does path MTU (Maximum Transmission Unit) discov‐
   ery.  This means the kernel will keep track of the MTU  to  a  specific
   target  IP  address and return EMSGSIZE when a UDP packet write exceeds
   it.  When this happens, the  application  should  decrease  the  packet
   size.   Path MTU discovery can be also turned off using the IP_MTU_DIS‐
   COVER socket option or the /proc/sys/net/ipv4/ip_no_pmtu_disc file; see
   ip(7)  for  details.   When  turned off, UDP will fragment outgoing UDP
   packets that exceed the interface MTU.  However, disabling  it  is  not
   recommended for performance and reliability reasons.
1 голос
/ 23 марта 2010

Используйте getsockopt с параметром SO_NREAD.

Из справочной страницы Mac OS X:

SO_NREAD возвращает количество данных во входном буфере, которое доступно для приема. Для сокетов, ориентированных на грамм данных, SO_NREAD возвращает размер первого пакета - это отличается от команды FIONREAD ioctl (), которая возвращает общий объем доступных данных.

...