Python UDP套接字半随机失败接收

Python UDP套接字半随机失败接收

问题描述:

我有一些问题,我猜它是代码。Python UDP套接字半随机失败接收

该应用程序用于'ping'一些定制的网络设备来检查它们是否还活着。它每隔20秒用一个特殊的UDP数据包对它们进行处理并期望得到响应。如果他们连续三次ping不回答,应用程序会向员工发送警告消息。

应用程序每天24小时运行一次(主要是2-5次)应用程序无法接收UDP数据包,精确时间为10分钟,然后一切恢复正常。在这10分钟内,只有1个设备似乎在回复,其他设备似乎已经死机。我已经能够从日志中推断出来。

我已经使用wireshark来嗅探数据包,并且我已经验证过ping数据包都出去了,所以网络部分似乎工作正常,一直到操作系统。电脑运行WinXPPro,有些没有配置防火墙。我在不同的计算机,不同的Windows安装和不同的网络上都有这个问题。

我真的不知道这里可能是什么问题。

我附上了执行所有网络的代码的相关部分。这是在与应用程序其余部分分离的线程中运行的。

我可以提前感谢您提供的任何洞察。

def monitor(self): 
    checkTimer = time() 
    while self.running: 
     read, write, error = select.select([self.commSocket],[self.commSocket],[],0) 
     if self.commSocket in read: 
      try: 
       data, addr = self.commSocket.recvfrom(1024) 
       self.processInput(data, addr) 
      except: 
       pass 

     if time() - checkTimer > 20: # every 20 seconds 
      checkTimer = time() 
      if self.commSocket in write: 
       for rtc in self.rtcList: 
        try: 
         addr = (rtc, 7) # port 7 is the echo port 
         self.commSocket.sendto('ping',addr) 
         if not self.rtcCheckins[rtc][0]: # if last check was a failure 
          self.rtcCheckins[rtc][1] += 1 # incr failure count 
         self.rtcCheckins[rtc][0] = False # setting last check to failure 
        except: 
         pass 

     for rtc in self.rtcList: 
      if self.rtcCheckins[rtc][1] > 2: # didn't answer for a whole minute 
       self.rtcCheckins[rtc][1] = 0 
       self.sendError(rtc) 
+0

不要忘记,UDP不能保证可靠的传输:http://en.wikipedia.org/wiki/User_Datagram_Protocol – 2012-07-18 07:50:41

+0

我知道这一点,但这里的遗留系统非常可靠地使用UDP 15年左右而系统的其他部分没有这样的问题。 – flowInTheDark 2012-07-18 07:57:06

你没有提到它,所以我不得不提醒你,因为你使用的是select()这个socket最好是非阻塞的。否则你的recvfrom()可以阻止。处理得当时应该不会发生,但很难从简短的代码片段中看出来。

然后,您不必检查UDP套接字的可写性 - 它始终是可写的。

现在真正的问题 - 你说的数据包进入系统,但你的代码没有收到它们。这很可能是由于套接字接收缓冲区的溢出。 ping命令的数量是否比过去15年增加了?您正在设置自己的ping响应风暴,并且可能没有足够快地读取这些响应,所以它们堆积在接收缓冲区中并最终被丢弃。

我的投资回报率的顺序建议:

  • 摊开ping请求,不要为自己设定了一个DDOS。每个迭代查询一个系统,并保持每个目标的最后检查时间。这将允许你将数据包的数量统统输出。
  • SO_RCVBUF增加到一个很大的值。这将使您的网络堆栈更好地处理数据包突发。
  • 在一个循环中读取数据包,即一旦您的UDP套接字可读(假设它是非阻塞的),读取,直到获得EWOULDBLOCK。这将为您节省大量的select()电话。
  • 看看您是否可以使用Linux recvmmsg(2)的某些高级Windows API(如果存在这种情况)为每个系统调用排队多个数据包。

希望这会有所帮助。

+0

其实套接字处于阻塞模式,但我已经有一些记录,证实我从来没有遇到过这个问题。至于可能的DDOS,这个问题发生在具有4个设备和20个系统(这是我们拥有的最大部署系统)的系统中,所以我不会相信它是DOS的问题。我会将您的建议带入代码并返回结果。谢谢! – flowInTheDark 2012-07-19 07:01:13

+0

使缓冲区变大没有帮助,奇怪的是。最后有什么帮助的是你的建议是在每次读取它时读取套接字,直到EWOULDBLOCK可读。现在它的工作方式应该如此。谢谢! – flowInTheDark 2012-08-07 13:06:43

UDP不保证可靠的传输。现在可以工作了,接下来的一个小时和第二年。然后在两年内它将无法沟通整整一个小时。

在某些情况下,数据包的路由路径可能会被阻塞。当TCP发生这种情况时,发件人会被告知丢失,并且发件人可能会尝试通过不同的路径路径发送它。由于UDP是“发送与忘记”传输协议,因此您可能会丢失一些统计数据包。

tl; dr使用TCP。

+1

请注意文本中提到我的wireshark嗅探并确认数据包实际进入系统的部分。 – flowInTheDark 2012-07-18 08:01:22