я могу прочитать ровно один пакет UDP из сокета? - PullRequest
8 голосов
/ 30 марта 2010

Используя API сокетов UNIX в Linux, есть ли способ гарантировать, что я прочитал один пакет UDP и только один пакет UDP? В настоящее время я читаю пакеты с неблокирующего сокета, используя recvmsg, с размером буфера, немного превышающим MTU нашей внутренней сети. Это должно гарантировать, что я всегда смогу получить полный пакет UDP, но я не уверен, что могу гарантировать, что никогда не получу более одного пакета за вызов recvmsg, если пакеты небольшие.

Справочные страницы recvmsg ссылаются на опцию MSG_WAITALL, которая пытается дождаться заполнения буфера. Мы не используем это, значит ли это, что recvmsg всегда будет возвращаться после чтения одной дейтаграммы? Есть ли способ гарантировать это?

В идеале я бы хотел кросс-UNIX-решение, но если его нет, есть ли что-то специфичное для Linux?

Ответы [ 3 ]

13 голосов
/ 30 марта 2010

recvmsg вернет вам один пакет, и это будет весь пакет (при условии, что буфер, который вы предоставляете, достаточно большой).

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

Функция recvmsg () должна получать сообщение от сокета в режиме соединения или в режиме без соединения.

«сообщение» означает ровно одно сообщение (или пакет)и

Для сокетов на основе сообщений, таких как SOCK_DGRAM и SOCK_SEQPACKET, все сообщение должно быть прочитано за одну операцию.

0 голосов
/ 13 июня 2018

Принятый ответ не дает четкого ответа на вопрос ОП, поскольку он упоминает размер буфера только попутно.

Я сейчас читаю пакеты с неблокирующего сокета, используя recvmsg, с размером буфера немного больше, чем MTU нашего внутреннего сеть.

Важно, чтобы ваш буфер был достаточно большим, чтобы вместить одну целую дейтаграмму. Датаграмма может быть до 65 536 байт. Когда большая датаграмма фрагментирована из-за MTU, она будет повторно собрана стеком, вы не будете знать об этом, вы просто ничего не получите, пока все фрагменты не будут получены и собраны обратно в исходную дейтаграмму. Если вы сделаете свой буфер немного больше, чем один MTU, например, 1600 байт, и вызовите recv () для входящей дейтаграммы, которая составляет 40 Кбайт, вы получите только первые 1600 байт.

0 голосов
/ 30 марта 2010

Один вариант (я говорю вариант) состоит в том, чтобы использовать pcap_next с использованием libpcap и разбирать его на части, чтобы увидеть, является ли это пакет udp. Вы можете сделать это с:

/* jump pass the ethernet header */
ipdata = (struct ip*)(packet + sizeof(struct ether_header));
length -= sizeof(struct ether_header);

(Заимствовано из tcpdump)

и затем протестируйте структуру ip, чтобы увидеть, является ли это пакет udp, выполнив:

if ( ipdata->ip_p == IPPROTO_UDP )

И если это не удается, продолжайте цикл (вызывая pcap_next), пока не получите свой пакет udp. Конечно, извлекать дейтаграмму udp сложнее, но она довольно хорошо позволяет вам проникнуть внутрь пакета. Обратитесь к источнику tcpdump, чтобы узнать, как извлекать информацию и что выходит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...