我有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路径不会改变我们。
此功能很可能在Linux下返回1500.
真正不清楚的是,许多答案之间似乎相互矛盾的是,这1500字节的大小不仅仅是我的有效载荷。它可能包括一些我无法控制的标题(即以太网标题+页脚,IPv4标题,UDP标题。)
从其他一些问题和答案来看,我觉得我可以发送1,500字节的数据而不会出现碎片,假设我的所有MTU都是1,500。
所以......哪个是真的?
我的数据缓冲区的大小可以等于MTU
我的数据缓冲区必须为MTU - sizeof(various-headers/footers)
P.S。网络是我们100%控制的局域网。数据包将使用UDP多播从一台主计算机传输到一组从计算机。中间只有一个1Gbps交换机。没什么。
答案 0 :(得分:1)
RFC-8085中定义的大小非常明确: UDP使用指南。
https://tools.ietf.org/html/rfc8085#section-3.2
有关有效载荷的大小计算有相关位。
要确定适当的UDP有效负载大小,应用程序必须从PMTU大小中减去IP标头的大小(包括任何IPv4可选标头或IPv6扩展标头)以及UDP标头的长度(8个字节)。此大小称为最大段大小(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计算必须考虑到这一点。
此处不包括以太网页眉和页脚的大小,因为它们对UDP数据包是透明的。