【问题标题】:Maximum UDP-packet number which can be stored in the socket buffer? (Ubuntu)可以存储在套接字缓冲区中的最大 UDP 数据包数? (Ubuntu)
【发布时间】:2018-07-09 12:18:19
【问题描述】:

客户:

import socket
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
msg = b"X"
for i in range(1500):
    s.sendto(msg,("<IP>",<PORT>))

服务器:

import socket
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.bind(("",>PORT>))
counter = 0
for i in range(1500):
    s.recv(1)
    counter += 1

我有两台机器 - 第一台使用 Windows7,第二台使用 Ubuntu 16.04。

现在的问题:

如果我尝试从客户端向服务器发送 1500 个 UDP 数据包(例如),那么:

  • Windows7 是客户端,Ubuntu16.04 是服务器: 服务器只接收 200 到 280 个数据包

  • Ubuntu16.04 是客户端,Windows7 是服务器: 服务器接收所有 1500 个数据包

我的第一个问题:

这是什么原因?操作系统有什么限制吗?

第二个问题:

是否可以在 Python 中优化套接字?

我知道 UDP 包可能会丢失 - 但最多丢失所有数据包的 4/5?

编辑: 为什么会有这样的问题? 想象一下,我有一个大型传感器网络……和一台服务器。每个传感器节点都应该将他的信息发送到服务器。服务器上的程序只能以异步方式进行编程——服务器只能在特定时间从套接字中读取数据。现在我想计算在服务器无法读取其缓冲区的时间段内,有多少传感器节点可以通过 UDP 数据包向服务器发送数据。有了缓冲区中可以存储多少个不同的 UDP 数据包的信息,我可以计算出可以使用多少个传感器节点...

【问题讨论】:

  • 如果我错了,请纠正我,但您每 1500 次迭代只接收 1 个字节?
  • 我的第一个猜测是windows防火墙设置,你检查过你尝试使用的端口是否打开了吗?
  • @Torxed:是的.. 但是消息应该是 200-250 字节长。现在我尝试了其他一些消息长度,并且收到的数据包更少。我如何才能确定缓冲区中可以存储多少个特定大小的不同数据包? :/ 为什么在操作系统上有一些差异?
  • @meissner:windows机器上接收数据包没有问题吗?但是我尝试将发送套接字绑定到特定端口并在 Windows 防火墙中打开该端口 - 结果相同,在 Ubuntu 机器上只收到 5 个数据包中的 1 个......我已经用 wireshark 检查了这个,并且wireshark告诉我windows-machine已经发送了1500个udp-packets..

标签: python windows udp ubuntu-16.04 python-sockets


【解决方案1】:

与其编写杂乱无章的评论线索,不如在这里解决问题。 正如redhat 所记录的那样,不同操作系统的默认值:在本文写作时刻是:

  • Linux:131071
  • Windows:无已知限制
  • Solaris:262144
  • FreeBSD,达尔文:262144
  • AIX:1048576

这些值应该对应于:

import socket
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
print(s.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF))

这些数字表示在任何给定时刻可以在套接字接收缓冲区中保存多少字节。这些数字可以在任何给定时间增加,但会为此缓冲区保留 RAM(或者至少我记得是这样)。

在 Linux(和一些 BSD 版本)上,要增加缓冲区,您可以使用 sysctl

sudo sysctl -w net.core.rmem_max=425984
sudo sysctl -w net.core.rmem_default=425984

这会将缓冲区设置为 416KB。如果您经常看到缓冲,您很可能会将其增加到几兆字节。

但是,缓冲区通常表明存在问题,因为您的计算机根本不应该有太多缓冲区。它是一种处理突然高峰的机制,并用作您的机器存储工作负载的小盘子。如果它满了,要么你有一个非常慢的代码需要变得更快,要么你需要相当多地卸载你的服务器。因为如果缓冲区填满 - 无论它有多大,最终都会再次变满。

假设您还可以通过以下方式从 Python 增加缓冲区大小:

s.setsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF, 1024)

但是,同样,如果您的操作系统被限制在某个屋顶 - 这将取代您在 python 程序中放置的任何值。

tl;博士:

每个操作系统都有基于优化/性能原因的限制。套接字、文件句柄(基本上任何 I/O 操作)都有它们。

这很常见,你应该找到很多关于它的信息。以上所有这些信息大多是通过搜索“linux udp recieve buffer”找到的。

另外,“windows 增加 udp 缓冲区大小”让我明白了这一点:Change default socket buffer size under Windows

最后说明

正如您所提到的,由于您使用的是 UDP,性能、数量等可能会有很大差异。由于速度的好处,它很容易丢失数据。服务器、驱动程序、NIC(尤其重要的是,一些 NIC 的硬件缓冲区有限,可能会导致这些问题)等都会影响您接收的数据。 Windows 在这些情况下也做了很多自动魔术,请确保将 Linux 机器调整为相同的参数。一个 UDP 数据包不仅包含您发送的数据量.. 还包含它之前的标头中的所有参数(在 IP 数据包中,例如 TTL、分片、ECN 等)。

例如,您可以调整您的 UDP 堆栈在特定负载下可以占用多少内存,以找出您的阈值下限(UDP 不会检查 RAM 使用情况)、压力阈值(负载下的内存管理)和最大值UDP 套接字可以使用每个套接字。

sudo sysctl net.ipv4.udp_mem

这是一篇来自 ESnet 的关于 UDP 调优的好文章:

除此之外,您正在调整自己的坟墓。最有可能的是,您的问题可以通过重新设计代码来解决。因为除非您实际上从网络推送 1-10GB/s,否则内核应该能够处理它,前提是您处理数据包的速度足够快,而不是将它们堆积在缓冲区中。

【讨论】:

    猜你喜欢
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多