首页 > 解决方案 > 确定最大 UDP 数据报大小的跨平台方法

问题描述

我正在尝试提高发送 UDP 数据报的 Python 程序的可移植性。

在 BSD 和 macOS 上,它访问net.inet.udp.maxdgramsysctl 以确定它可以在一个数据包中传输的最大字节数。(在我的 macOS 11.2 系统上,该值返回 9216。)Linux 上不存在此 sysctl。

有一个套接字选项SO_SNDBUF指示内核分配的发送缓冲区的大小。我可以检查它:

import socket
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
    max_dgram = s.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)

在 macOS 上,这返回相同的值 9216。但在 Linux 上,它返回 212992,这对于单个 UDP 数据包来说似乎太大了,所以我认为SO_SNDBUF查询不是正确的。

(另外,文档SO_SNDBUF说,“这个限制是计算为两倍的......选项值减去用于开销的 32 个字节。”这意味着实际的最大大小接近半兆字节。)

有没有办法做到这个跨平台?或者如果不是,在 Linux 上做这件事的正确方法是什么?

标签: pythonlinuxsocketsudp

解决方案


SO_SNDBUF 很大,因为 udp 可以分片。

在此处输入图像描述

似乎 9216 是 2^13(最后一个片段偏移)+ 1024(安全有效负载大小)

Linux 212992 是 /proc/sys/net/core/wmem_max 因为您可以在一个套接字上同时将数据包发送到几个或多个目的地,但对于 SOCK_STREAM 它加倍 2^13

如果客户端 IP 堆栈支持 ICMP,请使用https://stackoverflow.com/a/26524829/2101808 PMTU 发现。或者通过发送带有 DF 标志的数据包在应用层执行此操作。


推荐阅读