Python UDP套接字半随机接收失败
我有一个问题,我猜这是代码 该应用程序用于“ping”一些定制的网络设备,以检查它们是否处于活动状态。它使用一个特殊的UDP数据包每隔20秒ping一次,并期望得到响应。如果他们连续3次未能应答ping,应用程序将向员工发送警告消息 该应用程序正在全天候运行,并且每天有随机次数(通常为2-5次)应用程序在10分钟的准确时间内无法接收UDP数据包,此后一切恢复正常。在这10分钟内,只有一台设备似乎在应答,其他设备似乎已死亡。我能从日志中推断出来 我已经使用wireshark嗅探数据包,并且我已经验证了ping数据包的进出,所以网络部分似乎工作正常,一直到操作系统。这些计算机正在运行WinXPPro,有些没有配置任何防火墙。我在不同的计算机、不同的windows安装和不同的网络上遇到这个问题 我真的不知道这里可能有什么问题 我附上了代码的相关部分,它负责整个网络。这是在应用程序其余部分的单独线程中运行的 我提前感谢您提供的任何见解Python UDP套接字半随机接收失败,python,windows,sockets,udp,Python,Windows,Sockets,Udp,我有一个问题,我猜这是代码 该应用程序用于“ping”一些定制的网络设备,以检查它们是否处于活动状态。它使用一个特殊的UDP数据包每隔20秒ping一次,并期望得到响应。如果他们连续3次未能应答ping,应用程序将向员工发送警告消息 该应用程序正在全天候运行,并且每天有随机次数(通常为2-5次)应用程序在10分钟的准确时间内无法接收UDP数据包,此后一切恢复正常。在这10分钟内,只有一台设备似乎在应答,其他设备似乎已死亡。我能从日志中推断出来 我已经使用wireshark嗅探数据包,并且我已经验
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问题。我会将您的建议纳入代码中,并返回结果。谢谢奇怪的是,让缓冲区变大并没有帮助。最后的帮助是您建议在循环中读取套接字,直到每次我获得可读性时,我都会阻塞它。现在它的工作,因为它应该。非常感谢。