6

我有什么问题,我猜是代码。

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

该应用程序每天 24/7 运行,并且每天有随机次数(主要是 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)
4

2 回答 2

3

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

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

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

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

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

希望这可以帮助。

于 2012-07-18T12:32:48.010 回答
0

UDP 不保证可靠传输。这可以在现在、下一个小时和明年发挥作用。然后在两年内它将无法通信整整一个小时。

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

tl;博士使用 TCP。

于 2012-07-18T07:57:45.343 回答