Python UDP套接字半随机无法接收

时间:2012-07-18 07:48:22

标签: python windows sockets udp

我遇到问题,我猜这是代码。

该应用程序用于“ping”某些自定义网络设备,以检查它们是否还活着。它使用特殊的UDP数据包每隔20秒对它们进行一次ping操作并期望响应。如果他们连续3次没有应答,则应用程序会向员工发送警告消息。

应用程序全天候运行并且每天随机播放一次(主要是2-5次),应用程序无法在10分钟的精确时间内收到UDP数据包,之后一切都恢复正常。在那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)

2 个答案:

答案 0 :(得分:3)

你没有提到它,所以我必须提醒你,因为你使用select()该套接字最好是非阻塞的。否则您的recvfrom()会阻止。在处理得当时不应该真的发生,但很难从短代码片段中辨别出来。

然后你不必检查UDP套接字的可写性 - 它总是可写的。

现在针对真正的问题 - 您说数据包正在进入系统,但您的代码却没有收到它们。这很可能是由于套接字接收缓冲区溢出造成的。 ping目标的数量是否超过过去15年?您正在设置ping响应风暴,并且可能没有足够快地读取这些响应,因此它们堆积在接收缓冲区中并最终被丢弃。

我的投资回报率建议:

  • 传播ping请求,不要为自己设置DDOS。例如,每次迭代查询一个系统并保持每个目标的最后检查时间。这样可以平衡输出和输入的数据包数。
  • SO_RCVBUF增加到一个较大的值。这将使您的网络堆栈更好地处理数据包突发。
  • 在循环中读取数据包,即一旦您的UDP套接字可读(假设它是非阻塞的),一直读到EWOULDBLOCK。这样可以节省大量select()次电话。
  • 看看你是否可以使用Linux recvmmsg(2)沿线的某些高级Windows API(如果存在这样的话),为每个系统调用出列多个数据包。

希望这有帮助。

答案 1 :(得分:0)

UDP无法保证可靠的传输。现在,这可能会在下一个小时和明年发挥作用。然后在两年内它将无法沟通一整个小时。

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

tl; dr使用TCP。