套接字缓冲区中可以存储的最大UDP数据包数? (Ubuntu)

时间:2018-07-09 12:18:20

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

客户:

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数据包,我就可以计算出我可以使用多少个传感器节点。

1 个答案:

答案 0 :(得分:1)

这里没有问题的注释,而是写了几分钱。 正如redhat所述,在撰写本文时,不同OS:es的默认值为:

  • 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; dr:

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

这很常见,您应该在其中找到很多信息。以上所有这些信息主要是通过在“ Linux udp接收缓冲区”上进行搜索找到的。

此外,“ windows增加udp缓冲区的大小”使我着迷于此:Change default socket buffer size under Windows

最后的笔记

正如您提到的,由于您使用的是UDP,因此性能,数量等可能会有很大差异。由于速度的原因,容易造成数据丢失。服务器,驱动程序和 NIC 之间的距离(尤其重要,某些NIC的硬件缓冲区有限,可能导致这些情况)等因素都会影响您将收到的数据。在这种情况下,Windows也会自动执行很多操作,请确保将Linux计算机调整为相同的参数。 UDP数据包不仅包括您发送的数据量,还包括它之前的标头中的所有参数(IP数据包中的所有参数,例如TTL,Fragmentation,ECN等)。

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

sudo sysctl net.ipv4.udp_mem

这是一篇有关从ESnet进行UDP调整的好文章:

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