Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python UDP套接字半随机接收失败_Python_Windows_Sockets_Udp - Fatal编程技术网

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

Python UDP套接字半随机接收失败,python,windows,sockets,udp,Python,Windows,Sockets,Udp,我有一个问题,我猜这是代码 该应用程序用于“ping”一些定制的网络设备,以检查它们是否处于活动状态。它使用一个特殊的UDP数据包每隔20秒ping一次,并期望得到响应。如果他们连续3次未能应答ping,应用程序将向员工发送警告消息 该应用程序正在全天候运行,并且每天有随机次数(通常为2-5次)应用程序在10分钟的准确时间内无法接收UDP数据包,此后一切恢复正常。在这10分钟内,只有一台设备似乎在应答,其他设备似乎已死亡。我能从日志中推断出来 我已经使用wireshark嗅探数据包,并且我已经验

我有一个问题,我猜这是代码

该应用程序用于“ping”一些定制的网络设备,以检查它们是否处于活动状态。它使用一个特殊的UDP数据包每隔20秒ping一次,并期望得到响应。如果他们连续3次未能应答ping,应用程序将向员工发送警告消息

该应用程序正在全天候运行,并且每天有随机次数(通常为2-5次)应用程序在10分钟的准确时间内无法接收UDP数据包,此后一切恢复正常。在这10分钟内,只有一台设备似乎在应答,其他设备似乎已死亡。我能从日志中推断出来

我已经使用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)

UDP不能保证可靠的传输。这可以在现在、未来一小时和明年起作用。然后在两年内,它将无法沟通整整一个小时

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


tl;dr使用TCP。

您没有提到它,因此我必须提醒您,由于您使用的是
select()
,所以套接字最好是非阻塞的。否则,
recvfrom()
可能会被阻止。如果处理得当,不应该真的发生,但很难从简短的代码片段中分辨出来

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

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

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

  • 分散ping请求,不要为自己设置DDOS。例如,每次迭代查询一个系统,并保持每个目标的最后检查时间。这将允许您平衡进出的数据包数量
  • SO_RCVBUF
    增加到一个较大的值。这将允许您的网络堆栈更好地处理数据包突发
  • 在循环中读取数据包,即,一旦UDP套接字可读(假设它是非阻塞的),读取数据包直到获得
    ewoodblock
    。这将为您节省大量的
    select()
    调用
  • 看看是否可以使用一些与Linux类似的高级Windows API(如果存在这种情况的话),对每个系统调用的多个数据包进行出列

希望这有帮助。

不要忘记UDP不能保证可靠的传输:我知道,但是,这里的传统系统在15年左右的时间里都非常可靠地使用UDP,系统的其余部分没有此类问题。请注意文本中我提到的wireshark嗅探并确认数据包确实进入了系统。实际上套接字处于阻塞模式,但我有一些日志记录,证实我从未遇到过这个问题。至于可能的DDOS,这个问题发生在有4台设备和20台设备的系统中(这是我们拥有的最大的部署系统),因此我并不认为这是一个DOS问题。我会将您的建议纳入代码中,并返回结果。谢谢奇怪的是,让缓冲区变大并没有帮助。最后的帮助是您建议在循环中读取套接字,直到每次我获得可读性时,我都会阻塞它。现在它的工作,因为它应该。非常感谢。