c++ - 我可以在一个 UDP 数据包中发送多少数据并且仍然避免碎片?
问题描述
我有处理发送和接收 UDP 数据包的 C++ 类。到目前为止,我用那些来发送信号(PING、WAKEUP,...),换句话说,非常小的数据包,从来没有出现过问题。
现在我想发送大块数据(即0.5Mb),但为了优化丢包的可能性,我希望能够自己进行分片。首先,我编写了一个函数,它给出了 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 路径不会仅仅改变我们。
这个函数在 Linux 下很可能返回 1500。
许多答案之间真正不清楚并且似乎相互矛盾的是,这 1,500 字节的大小不仅仅是我的有效负载。它可能包括一些我无法控制的标头(即以太网标头+页脚、IPv4 标头、UDP 标头。)
从其他一些问题和答案来看,假设我所有的 MTU 都是 1,500,我感觉我可以发送 1,500 字节的数据而不会产生碎片。
那么......这是真的吗?
我的数据缓冲区的大小可以等于
MTU
我的数据缓冲区必须是
MTU - sizeof(various-headers/footers)
PS 网络是我们控制 100% 的 LAN。数据包将使用 UDP 多播从一台主计算机传输到一组从属计算机。两者之间只有一个 1Gbps 交换机。而已。
解决方案
The size is very clearly defined in RFC-8085: UDP Usage Guidelines.
https://www.rfc-editor.org/rfc/rfc8085#section-3.2
There is the relevant bit about the size calculation for the payload.
To determine an appropriate UDP payload size, applications MUST subtract the size of the IP header (which includes any IPv4 optional headers or IPv6 extension headers) as well as the length of the UDP header (8 bytes) from the PMTU size. This size, known as the Maximum Segment Size (MSS), can be obtained from the TCP/IP stack [RFC1122].
So in C/C++, this becomes:
#include <netinet/ip.h> // for iphdr
#include <netinet/udp.h> // for udphdr
int mss(udp.get_mtu_size());
mss -= sizeof(iphdr);
mss -= sizeof(udphdr);
WARNING: The size of the IP header varies depending on options. If you use options that will increase the size, your MSS computation must take that in account.
The size of the Ethernet header and footer are not included here because those are transparent to the UDP packet.
推荐阅读
- python - boto3 ec2 & django
- xamarin.android - 尝试在 Android 模拟器中启动默认项目时出现“已取消构建”Xamarin 消息
- python - 为什么单击()后Selenium脚本项目无法继续
- haskell - 使用“toList”函数创建自定义列表数据结构
- python - 如何在Python中创建一个在特定条件下从另一个表返回值的新列
- reactjs - 我应该保留一个全局共享组件,还是每个孩子使用一个?
- vue.js - 监听来自动态 Vue 组件的事件
- javascript - 使用从数组到函数的字符串作为变量
- c# - 创建此类的实例时如何将对 WinForm 控件的引用传递给类?
- ncurses - 在输入和一些自定义数据通道上都阻塞的终端控件库?