我可以在一个 UDP 数据包中发送多少数据并仍然避免碎片化?
How much data can I send in one UDP packet and still avoid fragmentation?
我有 C++ 类 可以处理发送和接收 UDP 数据包。到目前为止,我用它们发送信号(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 路径不会只对我们改变。
这个函数很可能return1500下Linux.
真正不清楚并且在许多答案之间似乎相互矛盾的是,这 1,500 字节大小不只是我的有效载荷。它可能包括一些我无法控制的 headers(即以太网 header + 页脚、IPv4 header、UDP header。)
从其他一些问题和答案来看,感觉我可以发送 1,500 字节的数据而不分片,假设我所有的 MTU 都是 1,500。
所以...哪个是真的?
我的数据缓冲区的大小可以等于 MTU
我的数据缓冲区必须是MTU - sizeof(various-headers/footers)
P.S。网络是我们100%控制的局域网。数据包将从一台主计算机传输到一组使用 UDP 多播的从属计算机。中间只有一个 1Gbps 交换机。仅此而已。
RFC-8085 中定义的大小非常明确:UDP 使用指南。
https://www.rfc-editor.org/rfc/rfc8085#section-3.2
有关于有效负载大小计算的相关位。
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].
所以在 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 header 的大小因选项而异。如果您使用会增加大小的选项,则您的 MSS 计算必须考虑到这一点。
此处未包括以太网的大小 header 和页脚,因为它们对 UDP 数据包是透明的。
我有 C++ 类 可以处理发送和接收 UDP 数据包。到目前为止,我用它们发送信号(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 路径不会只对我们改变。
这个函数很可能return1500下Linux.
真正不清楚并且在许多答案之间似乎相互矛盾的是,这 1,500 字节大小不只是我的有效载荷。它可能包括一些我无法控制的 headers(即以太网 header + 页脚、IPv4 header、UDP header。)
从其他一些问题和答案来看,感觉我可以发送 1,500 字节的数据而不分片,假设我所有的 MTU 都是 1,500。
所以...哪个是真的?
我的数据缓冲区的大小可以等于
MTU
我的数据缓冲区必须是
MTU - sizeof(various-headers/footers)
P.S。网络是我们100%控制的局域网。数据包将从一台主计算机传输到一组使用 UDP 多播的从属计算机。中间只有一个 1Gbps 交换机。仅此而已。
RFC-8085 中定义的大小非常明确:UDP 使用指南。
https://www.rfc-editor.org/rfc/rfc8085#section-3.2
有关于有效负载大小计算的相关位。
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].
所以在 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 header 的大小因选项而异。如果您使用会增加大小的选项,则您的 MSS 计算必须考虑到这一点。
此处未包括以太网的大小 header 和页脚,因为它们对 UDP 数据包是透明的。