【问题标题】:Cross-platform way to determine maximum UDP datagram size确定最大 UDP 数据报大小的跨平台方法
【发布时间】:2021-06-01 10:51:24
【问题描述】:

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

在 BSD 和 macOS 上,它访问 net.inet.udp.maxdgram sysctl 以确定它可以在一个数据包中传输的最大字节数。 (在我的 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 上的正确方法是什么?

【问题讨论】:

  • 请注意,某些路由器/交换机也可能有数据包限制。可以在新客户端的连接上进行协商序列。想法是发送越来越大的数据包并查看何时没有收到数据包,你有你的限制(测试必须在两个方向上进行)跨度>
  • IPv4 UDP有效载荷最大为65509字节(=65535-28),但通过路由器的实际限制一般为534字节。你不应该依赖比这个更大的值。

标签: python linux sockets udp


【解决方案1】:

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 标志的数据包。

【讨论】:

  • SO_SNDBUF 很大,允许同时等待多个传出的 UDP 数据包。在实践中,UDP 不能被分段,因为一个片段的丢失意味着整个数据报的丢失。
  • @user207421 你说得对。没有重传,但分片在本地网络中起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-12
  • 2011-10-07
  • 1970-01-01
  • 2020-05-25
  • 2015-05-17
  • 1970-01-01
相关资源
最近更新 更多