У меня есть классы C ++, которые обрабатывают отправку и получение пакетов UDP. Пока я использовал их для отправки сигналы (PING, WAKEUP, …) другими словами, очень маленькие пакеты и никогда не было проблем.
Теперь я хотел бы отправить большие блоки данных (т.е. 0,5 МБ), но чтобы оптимизировать возможность потери пакетов, я хочу иметь возможность выполнять свою собственную фрагментацию. Сначала я написал функцию, которая дает мне размер MTU:
int udp_server::get_mtu_size() const
{
if(f_mtu_size == 0)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));
if(ioctl(f_socket, SIOCGIFMTU, &ifr) == 0)
{
f_mtu_size = ifr.ifr_mtu;
}
else
{
f_mtu_size = -1;
}
}
return f_mtu_size;
}
Примечание: я знаю о PMTUD, который эта функция игнорирует. Как упомянуто ниже, это должно работать в контролируемой сети, поэтому путь MTU не только изменится для нас.
Эта функция может вернуть 1500 под Linux.
Что на самом деле неясно и кажется противоречивым во многих ответах, так это то, что размер в 1500 байт будет не только моей полезной нагрузкой. Возможно, он будет включать в себя некоторые заголовки, которые я не контролирую (например, заголовок Ethernet + нижний колонтитул, заголовок IPv4, заголовок UDP).
Из некоторых других вопросов и ответов кажется, что я могу послать 1500 байт данных без фрагментации, при условии, что все мои MTU 1500.
Итак … Что это правда?
Мой буфер данных может иметь размер, равный MTU
Мой буфер данных должен быть MTU - sizeof(various-headers/footers)
Постскриптум Сеть является локальной сетью, которую мы контролируем на 100%. Пакеты будут передаваться с одного главного компьютера на набор подчиненных компьютеров с использованием многоадресной рассылки UDP. Между ними есть только один коммутатор 1 Гбит / с. Ничего более.
Размер очень четко определен в RFC-8085: Правила использования UDP.
https://tools.ietf.org/html/rfc8085#section-3.2
Есть соответствующий бит о расчете размера для полезной нагрузки.
Чтобы определить подходящий размер полезной нагрузки UDP, приложения ДОЛЖНЫ вычесть размер заголовка IP (который включает в себя любые необязательные заголовки IPv4 или дополнительные заголовки IPv6), а также длину заголовка UDP (8 байтов) из размера PMTU. Этот размер, известный как максимальный размер сегмента (MSS), может быть получен из стека TCP / IP [RFC1122].
Таким образом, в C / C ++ это становится:
#include <netinet/ip.h> // for iphdr
#include <netinet/udp.h> // for udphdr
int mss(udp.get_mtu_size());
mss -= sizeof(iphdr);
mss -= sizeof(udphdr);
ПРЕДУПРЕЖДЕНИЕ: Размер IP-заголовка зависит от параметров. Если вы используете параметры, которые увеличивают размер, ваши вычисления MSS должны учитывать это.
Размер заголовка и нижнего колонтитула Ethernet здесь не учитывается, поскольку они прозрачны для пакета UDP.
Других решений пока нет …