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

flo*_*ark 6 python sockets windows udp

我有一些问题,我猜它是代码.

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

应用程序每周7天,每天24小时运行一次,每天随机播放一次(主要是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)
Run Code Online (Sandbox Code Playgroud)

Nik*_*sov 3

你没有提到它,所以我必须提醒你,既然你使用的是select()那个套接字,最好是非阻塞的。否则你recvfrom()可以阻止。如果处理得当,应该不会真正发生,但很难从简短的代码片段中看出。

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

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

我的建议(按投资回报率排序):

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

希望这可以帮助。