为什么“不分段”标志没有被禁用?

2024-06-01 03:07:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我在尝试使用setsockopt()设置不同的IP_MTU_DISCOVER值对udp包碎片的影响,发现(从man页,共ip(7))我需要将其值设置为IP_PMTUDISC_WANTIP_PMTUDISC_DONT以关闭“不分段”标志。但是,当我尝试发送数据包时,我得到socket.error: [Errno 90] Message too long。在

import IN, socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

hostname = 'localhost'
s.connect((hostname, 1060))

s.setsockopt(socket.IPPROTO_IP, IN.IP_MTU_DISCOVER, IN.IP_PMTUDISC_DONT)
mtu = s.getsockopt(socket.IPPROTO_IP, IN.IP_MTU)

print 'MTU:', mtu
s.send('.' * (mtu + 1))
print 'Big packet sent'

谢谢你


Tags: inipsockethostname碎片udpdiscoverprint
1条回答
网友
1楼 · 发布于 2024-06-01 03:07:34

让我们首先回顾一下PMTU是如何为UDP工作的。在

  1. IP端点从给定的MTU开始,通常是它的直接连接链路的MTU。在
  2. 发送数据包时,端点总是设置DF位。在
  3. 如果一个传输路由器决定它不能在不分割数据包的情况下发送数据包,它将返回一个ICMP Destination Unreachable包,错误代码为4,并返回下一个跃点MTU。在
  4. IP端点接收到无法访问的ICMP并调整其PMTU。在
  5. IP端点决定如何处理原始数据包(重传、信号应用层等)。在

需要注意的是,PMTU不会自动发生。在您(应用程序)开始发送实际数据之前,没有内置的探测包可以找到MTU。在

因此,Linux使用以下标志控制(对于数据报):

  • IP_PMTUDISC_WANT执行上述PMTU。如果应用程序发送的数据包对于已知的MTU来说太大了,套接字层将对其进行分段。传出数据包(包括碎片)将设置DF位。在
  • IP_PMTUDISC_DONT不要执行PMTU发现。在
  • IP_PMTUDISC_DO做PMTU发现。如果应用程序发送的数据包对于已知MTU来说太大,则向应用程序发送错误。在
  • IP_PMTUDISC_PROBE设置DF位以执行PMTU发现,但忽略当前学习的MTU。因此,如果应用程序发送的数据包太大,它无论如何都会尝试将其发送出去。这有助于不时地发送一个探测器,看看PMTU是否没有增加。在

现在需要注意的一点是,IP_PMTUDISC_DONT没有指定如果数据包实际上大于当前MTU(即直接链接的MTU)时该怎么做。所以最有可能的是,这个选择由接口来决定,接口实际上必须发送数据包。由于DF位没有被发送,大多数接口实际上应该对包进行分段。但是,您使用的是链接本地接口,它通常是一个功能稍差的软件接口。在您的发行版中,这可能不支持碎片,因此发送错误。这很有道理,从我的机器上取下这个输出:

In [6]: s.getsockopt(socket.IPPROTO_IP, 14) #14 = IP_MTU, just wasn't in my python lib.
Out[6]: 16436

这表明链路本地接口的MTU在网络方面是相当巨大的,那么它为什么要从支持碎片化开始呢。也就是说,在我的系统中,这实际上运行得很好。在

相关问题 更多 >