将UDP数据发送到python套接字的多个客户端正在迷失

时间:2018-05-01 23:17:41

标签: python sockets udp buffer

我有一个python套接字读取器,每分钟监听来自大约5000个客户端的传入UDP数据包。当我开始推出它时工作正常但现在我已经有大约4000个客户端丢失了大约50%的数据。虚拟机有足够的内存和CPU所以我认为它和#39;服务器上的UDP套接字侦听器会立即获取太多数据。通过cron,客户每分钟都会发送这些数据:

site8385','10.255.255.255','1525215422','3.3.0-2','Jackel','00:15:65:20:39:10'

这是我的侦听器脚本的套接字阅读器部分。

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
port = 18000
s.bind(('', port))

while True:
   # Establish connection with client.

   d = s.recvfrom(1024)

缓冲区大小是否太小?如何确定进入的数据包的大小,以便我可以调整1024值?

1 个答案:

答案 0 :(得分:0)

每60秒,你会得到约5000条消息。你按顺序处理它们,它需要相当多的时间"时间很快,你的一个缓冲区就满了,你的操作系统,你的网卡或你的路由器开始丢弃数据包。 (很可能它是你的内核为这个特定套接字留出的缓冲区,并且内核正在丢弃数据包,但所有其他选项也是可能的。)

您可以尝试增加这些缓冲区。这将给自己带来更多的"允许滞后时间",因此在内核开始丢弃数据包之前你可以进一步落后。如果你想走这条路,第一步是setsockopt来提高SO_RCVBUF值,但你真的需要了解这里可能涉及的所有问题。 1

如果你控制客户端代码,你也可以让客户端错开他们的数据包(例如,在random.random() * 55之前只在send睡觉。)

但尝试尽快为这些数据包提供服务可能会更好,并在后台进行处理。 2

尝试在线程中执行此操作可能是理想的,但它也可能非常繁琐,以便正确。一个更简单的解决方案是只使用后台线程或它们的池:

def process_msg(d):
    # your actual processing code

with concurrent.futures.ThreadPoolExecutor(max_workers=12) as x:
    while True:
        d = s.recvfrom(1024)
        x.submit(process_msg, d)

可能实际上没有帮助。如果你的处理是CPU绑定的而不是I / O绑定的,那么后台线程将只用主线程来攻击GIL。如果您使用的是Python 2.7或3.2或其他旧版本,即使是I / O绑定的线程也会在某些情况下发生干扰。但无论哪种方式,都可以轻松解决:只需将ThreadPoolExecutor更改为ProcessPoolExecutor(可能会将max_workers降低至比您拥有的核心数少1个确保接收代码可以拥有一个完整的核心。

<子> 1。 Redhat在Network Performance Tuning上有一个很好的文档。从系统管理员的角度来看,它比程序员的写得更多,它希望你知道或者知道如何查找大量的背景信息 - 但它应该是如果你愿意这样做,那就很有帮助。如果你想走这条路,你可能还想尝试搜索Server Fault而不是Stack Overflow。

<子> 2。当然,如果要处理每分钟的消息需要花费超过一分钟的时间,那么队列将会变得越来越长,最终一切都将以灾难性的方式失败,这比只是丢掉一些数据包直到你赶上......但希望这不是问题。