У меня есть немного тестовой программы, которая отправляет много udp пакетов между клиентом-> сервер-> клиент (тест ping/вони). Пакеты являются фиксированным размером на каждом выполнении (в последний раз выполненный, макс. допустимый размер udp пакета), я заполняю пакеты случайными данными за исключением начала каждого пакета, который содержит пакетное число. Таким образом, мне только интересно видеть, получаю ли я все пакеты назад в клиенте.
Я использую sendto () и recvfrom (), и я только считал sizeof (packet_number) (который в этом случае является интервалом). Что происходит с остальной частью данных? Это заканчивается в волшебной стране (отбрасывается)? или новый пакет, который прибывает, добавляется к этим "старым" данным?
(использование Linux)
Каждое чтение из UDP сокета снимает одну целую датаграмму с приемного буфера сокета ядра, независимо от того, каков размер вашего пользовательского буфера. То есть:
MSG_TRUNC
в flags
, так что recv(2)
вернет всю длину датаграммы, а не только ту часть, которую вы прочитали в буфер userland. Надеюсь, это поможет.
Чтобы ответить на ваш первый вопрос, отбрасываются ли данные? Да, отбрасываются. Протоколы 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 - это дейтаграммный протокол со строгими границами сообщений. Поэтому каждый приходящий пакет рассматривается как полная самодостаточная дейтаграмма; данные не добавляются.
Я не проверял это, но, судя по моей интерпретации man-страницы, он всегда будет отбрасываться. Это кажется разумным, поскольку иначе не было бы способа определить начало следующего пакета.
Есть два способа обнаружить усечение:
Используйте флаг MSG_TRUNC
. recvfrom
тогда вернет истинный размер пакета, даже если он не поместился в предоставленный буфер. Таким образом, вы можете просто проверить, больше ли возвращаемое значение, чем len
, который вы указали в качестве аргумента.
Используйте recvmsg
и проверьте возвращаемую структуру на наличие флага MSG_TRUNC
.
Чтобы избежать усечения, используйте буфер 64k. UDP-пакеты не могут быть больше этого размера (16-битное поле длины в протоколе).