Путаница в отношении UDP / IP и sendto / recvfrom возвращаемых значений - PullRequest
2 голосов
/ 23 апреля 2009

Я впервые работаю с сокетами UDP в C ++, и я не уверен, что понимаю, как они работают. Я знаю, что sendto / recvfrom и send / recv обычно возвращают количество байтов, фактически отправленных или полученных. Я слышал, что это значение может быть сколь угодно малым (но не менее 1) и зависит от того, сколько данных находится в буфере сокета (при чтении) или сколько свободного места осталось в буфере (при записи).

Если sendto и recvfrom гарантируют, что только один байт будет отправлен или получен за раз, а дейтаграммы могут быть получены не по порядку, как может любой протокол UDP оставаться связным? Не означает ли это, что байты в сообщении могут быть произвольно перетасованы, когда я их получу? Есть ли способ гарантировать, что сообщение будет отправлено или получено сразу?

Ответы [ 4 ]

3 голосов
/ 23 апреля 2009

Это немного сильнее этого. UDP доставляет полный пакет; размер буфера может быть сколь угодно мал, но он должен включать в себя все данные, отправленные в пакете. Но есть и ограничение по размеру: если вы хотите отправить много данных, вы должны разбить их на пакеты и иметь возможность самостоятельно собрать их. Это также не гарантированная доставка, поэтому вам нужно проверить, чтобы все прошло.

Но так как вы можете реализовать все TCP с UDP, это должно быть возможно.

обычно с помощью UDP вы создаете небольшие дискретные пакеты.

Метафорически, думайте о UDP как о отправке открыток, а TCP - как о телефонном звонке. Когда вы отправляете открытку, у вас нет гарантии доставки, поэтому вам нужно сделать что-то вроде возврата подтверждения. Во время телефонного звонка вы знаете, что соединение существует, и сразу слышите ответы.

1 голос
/ 21 марта 2012

У меня есть клиентская программа, которая использует блокировку выбора (параметр времени ожидания NULL) в потоке, предназначенном для ожидания входящих данных на сокете UDP. Несмотря на то, что это блокировка, выборка иногда возвращалась бы с указанием, что единственный дескриптор чтения был «готов». Последующее recvfrom вернуло 0.

После некоторых экспериментов я обнаружил, что по крайней мере в Windows отправка UDP-пакета на порт хоста, который не ожидает, что это может привести к последующему recvfrom с получением 0 байтов. Я подозреваю, что с другого конца может прийти какое-то уведомление об отказе. Теперь я использую это как напоминание о том, что я забыл запустить процесс на сервере, который ищет входящий трафик клиента.

Кстати, если я вместо этого "отправлю" действительный, но неиспользуемый IP-адрес, то выбор не возвращает состояние готовности и блокируется, как ожидалось. Я также обнаружил, что блокирующие и неблокирующие сокеты не имеют значения.

1 голос
/ 23 апреля 2009

На самом деле вы можете отправить дейтаграмму UDP длиной 0 байт. Все, что отправляется, это заголовки IP и UDP. UDP recvfrom () на другой стороне вернется с длиной 0. В отличие от TCP, это не означает, что узел закрыл соединение, потому что с UDP нет «соединения».

1 голос
/ 23 апреля 2009

Нет. С sendto вы отправляете пакеты, которые могут содержать до одного байта. Если вы отправите 10 байтов в качестве одного вызова sendto, эти 10 байтов будут отправлены в один пакет, который будет получен согласованным, как вы ожидаете.

Конечно, если вы решите отправить эти 10 байтов один за другим, каждый из них с помощью вызова sendto, тогда вы действительно отправите и получите 10 разных пакетов (каждый из которых содержит 1 байт), и они могут быть в произвольном порядке. .

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

...