UDP中的MTU如何为65535,但以太网不允许帧大小超过1500字节


11

我正在使用100 Mbps的快速以太网,其帧大小小于1500字节(根据我的教科书,有效负载为1472字节)。这样,我能够发送和接收消息大小为65507字节的UDP数据包,这意味着数据包大小为65507 + 20(IP报头)+ 8(UDP报头)= 65535。

如果帧的有效负载大小本身最大为1472字节(根据我的教科书),那么IP的数据包大小如何大于此处的65535?

我使用发件人代码作为

char buffer[100000];
for (int i = 1; i < 100000; i++)
{
    int len = send (socket_id, buffer, i);
    printf("%d\n", len);
}

接收方代码为

while (len = recv (socket_id, buffer, 100000))
{
     printf("%d\n". len);
}

我观察到send returns -1i > 65507recv打印或接收的分组maximum of length 65507

Answers:


11

UDP数据报与MTU大小无关,您可以将其设置成您喜欢的最大大小,直到上面提到的最大64K。您甚至可以在整个数据包中发送其中一个,只要您使用的巨型帧的大小大于大型数据报的大小。

然而,巨型框架必须由框架将要经过的所有设备来支撑,这是一个问题。出于实际目的,以太网帧是最常见的传输大小,其MTU约为1500字节,我会说1500向前,但并非总是如此。当您创建一个大于基础MTU的UDP数据报(如所示,该MTU通常是以太网)时,它将被悄悄地分解为1500个字节的帧。如果您对该流量进行tcpdump,则将在MTU边界看到许多数据包中断,这些数据包将设置更多的分片标志以及分片编号。第一个数据包的分片号为0,设置了更多的分片,最后一个数据包的分片号为非零,没有设置更多的分片。

那为什么要在意呢?实现细节实际上很重要。碎片会损害网络性能,不再是一个大问题,而是一个需要注意的问题。如果使用了巨大的数据报,那么如果丢失任何片段,整个数据报将需要重新发送。同样,在大批量生产时,如今这些都是可以完全实现的批量生产,因此在重新组装时可能会错配框架。还可能存在使碎片化的UDP数据包遍历企业防火墙配置(负载均衡器将数据包散布出去)的问题,如果一个碎片位于一个防火墙上,而另一个碎片位于另一个防火墙上,则流量将因为不完整而被丢弃。

因此,请勿创建大于MTU大小碎片的UDP数据报,除非您必须这样做,并且如果必须指定之间进行通信的基础结构处于关闭状态(相同的子网关闭状态),此时巨型帧可能是一个不错的选择。


有关“更多片段标志”的良好信息。这是UDP标头中还是IP标头中的标志?
约翰·耶稣

注意:如果数据会碎片化,某些操作系统将不会传输UDP。IE Linux文档,By default, Linux UDP does path MTU (Maximum Transmission Unit) discovery. This means the kernel will keep track of the MTU to a specific target IP address and return EMSGSIZE when a UDP packet write exceeds it.
Rahly

2

IP层将在发送端对您的数据包进行分段,然后再将其重新组合到接收端,然后再将其传递给UDP。从UDP层,您无法真正分辨出数据包已被分割。如果使用Wireshark之类的数据包捕获工具,则应该能够看到您的计算机正在接收限于MTU的IP数据包。


1

事实证明,允许TCP / IP堆栈根据需要对数据包进行分段比与发送单个数据包相比开销要低得多。


1
您是说TCP / IP本身正在碎片化和重组吗?如果是,那么为什么人们总是说您的代码应该在接收方进行重组。到目前为止,我还没有观察到零散的情况,但是看到了很多论坛都在这样说,甚至人们也接受它。

对于我们这些面临OSI模型挑战的人,您能否在回答中添加更多细节?
罗伯特·哈维

我有点笼统,因为我不知道这是否是家庭作业。这是一个折衷方案:由于UDP无法保证传送,因此如果丢弃任何数据包片段,整个数据包都会丢失。如果您想在UDP上进行可靠的传输,则需要自己处理所有这些操作。但是,如果您正在执行(例如)流协议(或采用类似流的路径的UDP上的NFS),则只需丢弃那些数据包或在需要时经过较长的延迟后重新传输较大的数据包,则开销较低。您需要在协议功能和协议开销之间达到平衡。
geekosaur 2011年

1

UDP对MTU一无所知。UDP数据包的大小可以在8到65535字节之间。UDP下的协议层可以发送特定大小的数据包,或者如果太大则拒绝发送错误的数据包。

UDP下的层通常是IP,即IPv4或IPv6。IP数据包的大小可以从20(IPv4)/ 40(IPv6)到65535字节,与UDP相同。但是,IP支持一种称为碎片的机制。如果IP数据包的大小大于下一层可以传输的大小,则IP可以将单个数据包拆分为多个称为片段的数据包。实际上,每个片段都是一个自己的IP数据包(具有自己的IP头),并且还自己发送到目的地。然后,目标的任务是收集所有片段并从中重建完整的数据包,然后再将接收的数据传递到下一个更高的层(例如UDP)。

以太网协议只能传输有效载荷介于46到1500字节之间的帧(有例外,但这不在此答复的范围之内)。如果有效载荷数据小于46字节,则将其填充为有效的46字节。如果有效载荷数据超过1500个字节,则接口将拒绝接受它。如果发生这种情况,则由IP层决定是对数据包进行分段,以便没有分段大于1500个字节,或者如果已为此特定连接禁用或禁止分段,则向下一个更高层报告错误。

通常应避免碎片,因为

  • 在发送方浪费资源。
  • 它浪费了接收方的资源。
  • 对于相同数量的有效负载数据,它增加了协议开销。
  • 如果单个片段丢失,则整个数据包都会丢失。
  • 如果单个片段损坏,则整个数据包都会损坏。
  • 如果重新发送,则必须重新发送所有片段。

这就是为什么TCP会智能地采用其帧大小,以便数据包从不需要IP对其进行分段的原因。这可以通过禁止IP对数据包进行分段来完成,如果IP报告数据包太大而无法发送,则TCP会减小帧大小并重试,直到不再报告错误为止。

但是,对于UDP来说,这将是应用程序本身的任务,因为UDP是“哑”协议,它没有自己的管理逻辑,这使其非常灵活,快速和简单。

始终可传输的唯一UDP大小是576减去8个字节的UDP标头和减去20(v4)/ 40(v6)字节的IP标头,因为IP标准要求每个IP主机都必须能够接收带有总大小为576个字节。如果您的协议实现不能接受至少那个大小的数据包,则它不是标准的。但是请注意,该标准不会说没有分段的576,因此即使是576字节的IP数据包也可能会在两个主机之间分段。

无需分段即可传输的唯一数据包大小是IPv4的24个字节和IPv6的56个字节,因为一个片段的最小IP标头为20/48字节(v4 / v6),并且一个片段必须至少具有4/8字节(v4 / v6)有效负载数据。因此,IP层以下的传输系统至少不能传输这些大小的数据包,因此不能用于传输IP流量。

在任何人评论IPv6标头只有40个字节之前:是正确的,但是与IPv4标头不同,标准IPv6标头没有用于分段的标头字段。如果必须对数据包进行分段,则必须在IPv6基本头下方添加分段扩展头,并且此扩展头的长度为8个字节。同样与IPv4不同,IPv6中的分段偏移是以8个字节而不是4个字节为单位进行计数的,因此,在IPv6的情况下,分段只能携带8字节倍数的有效负载。


0

要回答您的问题,“如果帧的有效负载大小本身最大为1472字节(根据我的教科书),那么IP的数据包大小如何大于此处的65535?”

这是由于称为UFO的卸载功能(UDP碎片卸载)所致。请参考链接。

您可以分别通过ethtool -k ethX和ethtool -K ethX验证和切换卸载功能。


0

如果要监视传出帧,则网络适配器可能支持分段卸载,并且已启用它。在启用分段卸载的情况下,网卡本身会处理将数据包/帧分段为适当大小,而不是网络堆栈。这样可以释放计算机中的CPU来执行其他任务,从而提高性能。在linux上,“ ethtool -k [device]”将显示卸载标志。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.