我写了一个简单的Python程序来发送UDP数据报。
import socket
client_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
host_name = socket.gethostname()
host_ip = '1.2.3.4'
print(host_ip)
port = 8080
message = b'0' * 65500
client_socket.sendto(message,(host_ip,port))
当我运行此代码时,它成功发送了 UDP 数据包。这是wireshark日志,
我的无线接口的 MTU 是 1500,这是我通过运行ip link
命令找到的。
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno2: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN mode DEFAULT group default qlen 1000
link/ether 58:11:22:82:c2:ec brd ff:ff:ff:ff:ff:ff
altname enp0s31f6
3: wlo1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DORMANT group default qlen 1000
link/ether f4:26:79:33:7c:96 brd ff:ff:ff:ff:ff:ff
altname wlp0s20f3
我读到不能发送大于接口 MTU 的数据包,那么 UDP 数据包是如何传输的呢?有人可以向我解释一下这里发生了什么吗?
PS:我尝试将其发送到我拥有的服务器,并且我也能够收到该消息。
IPv4 和 IPv6 都支持传输层以下的分段,尽管它并不总是能正常工作(某些网络不返回正确的路径 MTU 指示,某些网络直接丢弃分段),但在这种情况下,操作系统知道其本地MTU 并将相应地对数据包进行分段。
在您的情况下,数据包在 IP 层进行分段,但操作系统使用硬件卸载,因此分段实际上由您的 NIC 处理,并且对于数据包捕获不可见。(这可以提供更好的性能,因为操作系统不需要对多个数据包进行排队并在内存中复制有效负载数据块。)
用于
ethtool -k wlan0 | grep -v '\[fixed\]'
查看可以打开/关闭的卸载功能。这很可能是“generic-segmentation-offload”或“gso”;您可以使用 暂时禁用它ethtool -K wlan0 gso off
。此外,您还可以通过setsockopt() 设置一个套接字选项来选择不使用碎片;send() 调用将为太大的数据包返回错误代码。对于 IPv4,该选项为“IP_MTU_DISCOVER”,对于 IPv6,该选项为“IPV6_MTU_DISCOVER”。看
man 7 ip
。(如果您的 Python 版本没有这些常量,请在 /usr/include 中查找实际值 - 它们应该用于
10
IP_MTU_DISCOVER 和23
IPV6_MTU_DISCOVER。例如,setsockopt(SOL_IP, 10, False)
。)(顺便说一句,Wi-Fi 接口的潜在最大 MTU 约为 2304 – 它们只是默认为 1500,以保持与标准以太网配置 1500 兼容。)