чтение частично из сокетов

У меня есть немного тестовой программы, которая отправляет много udp пакетов между клиентом-> сервер-> клиент (тест ping/вони). Пакеты являются фиксированным размером на каждом выполнении (в последний раз выполненный, макс. допустимый размер udp пакета), я заполняю пакеты случайными данными за исключением начала каждого пакета, который содержит пакетное число. Таким образом, мне только интересно видеть, получаю ли я все пакеты назад в клиенте.

Я использую sendto () и recvfrom (), и я только считал sizeof (packet_number) (который в этом случае является интервалом). Что происходит с остальной частью данных? Это заканчивается в волшебной стране (отбрасывается)? или новый пакет, который прибывает, добавляется к этим "старым" данным?

(использование Linux)

9
задан NomadAlien 18 June 2010 в 11:30
поделиться

3 ответа

Каждое чтение из UDP сокета снимает одну целую датаграмму с приемного буфера сокета ядра, независимо от того, каков размер вашего пользовательского буфера. То есть:

  • Если ваш буфер больше, чем следующая ожидающая датаграмма, вы прочитаете меньше, чем размер вашего буфера.
  • Если ваш буфер меньше, вы прочитаете только размер буфера, а остальные данные будут отброшены.
  • Вы можете установить опцию MSG_TRUNC в flags, так что recv(2) вернет всю длину датаграммы, а не только ту часть, которую вы прочитали в буфер userland.

Надеюсь, это поможет.

14
ответ дан 4 December 2019 в 09:35
поделиться

Чтобы ответить на ваш первый вопрос, отбрасываются ли данные? Да, отбрасываются. Протоколы IP и ARP вступают в игру, когда ваш пакет превышает MTU пути. Path MTU - это максимальная единица передачи данных на пути между клиентом и сервером. Если предположить, что ваша сетевая карта является стандартной картой ethernet, то ваш максимальный MTU равен 1500. Теперь предположим, что MTU всего пути между вашим клиентом и сервером равно 1500. В этом сценарии, если вы отправите любой пакет, размер которого превышает 1472 байта (1500 - (20 байт ip-заголовок) - (8 байт UDP-заголовок)), то произойдет фрагментация IP. В этом случае IP-уровень будет разбивать пакет на фрагменты, чтобы соответствовать MTU канала Ethernet. Теперь, перед отправкой любых данных, необходимо определить MAC-адрес получателя. Поэтому внезапно протокол ARP получит несколько IP-фрагментов, запрашивающих разрешение одного и того же IP- и MAC-адреса. Затем произойдет следующее: ARP инициирует ARP-запрос для первого полученного пакета и будет ждать ARP-ответа. Во время ожидания ARP отбросит все фрагменты, выполняющие один и тот же ARP-запрос, и поставит в очередь только последний полученный фрагмент. Поэтому, если вы отправляете пакет размером более 1472 байт, не ожидайте получить весь пакет на другом конце, если ваш ARP-кэш пуст.

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

5
ответ дан 4 December 2019 в 09:35
поделиться

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

Есть два способа обнаружить усечение:

Используйте флаг MSG_TRUNC. recvfrom тогда вернет истинный размер пакета, даже если он не поместился в предоставленный буфер. Таким образом, вы можете просто проверить, больше ли возвращаемое значение, чем len, который вы указали в качестве аргумента.

Используйте recvmsg и проверьте возвращаемую структуру на наличие флага MSG_TRUNC.

Чтобы избежать усечения, используйте буфер 64k. UDP-пакеты не могут быть больше этого размера (16-битное поле длины в протоколе).

3
ответ дан 4 December 2019 в 09:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: