Winsock udp recv не получает все данные даже внутри цикла - PullRequest
0 голосов
/ 29 мая 2019

У меня есть некоторый UDP-код recv, использующий winsock, в частности AF_INET, SOCK_DGRAM и IPPROTO_UDP. Вызов recv существует в цикле, который читает, пока не будут получены все данные. Проблема в том, что я получаю только частичные данные каждый раз. Более того, мне даже не нужен цикл, так как я вижу, что все данные существуют в одном пакете. В Wireshark я вижу, что реальная длина данных составляет 299 байтов. Wireshark успешно видит весь пакет, поэтому я знаю, что отправитель пакетов работает правильно.

С моим UDP-кодом Windows я получаю только 8 байт, пока не вернется мой метод приема. Я вижу, что код UDP останавливается, когда видит байт 00. Wireshark может читать за этими 00 байтами, но Windows udp recv не может читать за ним. Кажется, что Windows видит 00 как конец и поэтому приходит к выводу, что пакет занимает всего 8 байтов.

Я посмотрел на заголовок в wireshark и вижу, что указанная длина верна, поэтому я очень озадачен, почему он читает только 8 байтов. Заранее благодарю за помощь.

Вот так выглядит мой приемный вызов для справки:

int ret = recv(socket, buffer, 1500, 0);

ret становится 8, а буфер, который был выделен для 1500 байтов, заполняется только 8 байтами

1 Ответ

0 голосов
/ 29 мая 2019

UDP ориентирован на сообщения, а не на поток, как TCP.

В UDP только способ, которым recv() вернул бы 8 байтов, если либо:

  • Вы устанавливаете для параметра len значение > 8, и принимается датаграмма, содержащая ровно 8 байтов.

  • вы устанавливаете для параметра len значение == 8, и принимается дейтаграмма, содержащая более 8 байтов.

Учитывая ваше утверждение, что вы устанавливаете len на 1500, единственная возможность состоит в том, что полученная дейтаграмма содержит только 8 байтов, а не 299 байтов, как вы заявляете.

В отличие от TCP, в UDP вы не можете читать дейтаграммы по частям, чтение - это операция «все или ничего» (если вы не просматриваете данные, которые вы не делаете). В UDP recv() / recvfrom() считывает целые дейтаграммы за раз, и если предоставленный буфер слишком мал для приема данных (чего в данном случае нет), то сообщается об ошибке WSAEMSGSIZE, и данные усеченный, отбрасывая остальные данные, которые не помещаются в буфер.

Нулевые байты 00, которые вы описываете, не оказывают никакого влияния на способность recv() / recvfrom() читать всю дейтаграмму. Дейтаграмма имеет длину полезной нагрузки, и recv() / recvfrom() будет считывать до этой длины полезной нагрузки или указанного размера буфера, в зависимости от того, что меньше, независимо от фактического содержимого полезной нагрузки.

Так что, скорее всего, в вашем коде recv() просто не получает дейтаграмму, которую вы ожидаете.

Например, чтобы вообще использовать recv() в UDP, необходимо сначала connect() сокет UDP связать его с конкретным одноранговым IP / портом, что позволит recv() игнорировать входящие дейтаграммы от других одноранговых узлов. (и для send() для отправки дейтаграмм конкретному узлу). Может быть, вы connect 'выводите свой сокет UDP не к тому узлу и, таким образом, читаете дейтаграммы, предназначенные для чего-то другого. Или, может быть, вы connect обращаетесь к правильному узлу, и он действительно отправляет 8-байтовую дейтаграмму, которую вы не ожидаете.

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

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