2012-07-18 20 views
6

Tengo un problema con algo y supongo que es el código.Socket de Python UDP que falla al recibir semi-aleatoriamente

La aplicación se utiliza para 'hacer ping' en algunos dispositivos de red personalizados para comprobar si están activos. Los lanza cada 20 segundos con un paquete UDP especial y espera una respuesta. Si no responden 3 veces consecutivas, la aplicación envía un mensaje de advertencia al personal.

La aplicación se ejecuta 24/7 y durante un número aleatorio de veces al día (2-5 en su mayoría) la aplicación no puede recibir paquetes UDP durante un tiempo exacto de 10 minutos, después de lo cual todo vuelve a la normalidad. Durante esos 10 minutos, solo 1 dispositivo parece estar respondiendo, otros parecen muertos. Que he podido deducir de los registros.

He utilizado wireshark para olfatear los paquetes y he verificado que los paquetes de ping salen Y entran, por lo que la parte de la red parece funcionar bien, todo el camino hasta el sistema operativo. Las computadoras están ejecutando WinXPPro y algunas no tienen ningún firewall configurado. Estoy teniendo este problema en diferentes computadoras, diferentes instalaciones de Windows y diferentes redes.

Estoy realmente perdido sobre cuál podría ser el problema aquí.

Estoy adjuntando la parte relevante del código que hace toda la red. Esto se ejecuta en un hilo separado del resto de la aplicación.

Le agradezco de antemano cualquier información que pueda proporcionar.

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) 
+0

no olvide que UDP no garantiza la transmisión confiable: http://en.wikipedia.org/wiki/ User_Datagram_Protocol –

+0

Estoy enterado de eso, pero el sistema heredado aquí está usando UDP bastante confiablemente durante 15 años más o menos y el resto del sistema no tiene tales problemas. – flowInTheDark

Respuesta

3

No lo menciona, así que tengo que recordarle que ya que está usando select(), es mejor que la toma sea no bloqueante. De lo contrario, su recvfrom() puede bloquear. En realidad, no debería suceder cuando se trata adecuadamente, pero es difícil distinguirlo del fragmento de código corto.

Entonces no tiene que comprobar el socket UDP para la capacidad de escritura, siempre se puede escribir.

Ahora, para el verdadero problema, está diciendo que los paquetes están ingresando al sistema, pero su código no los recibe. Esto es muy probablemente debido al desbordamiento del búfer de recepción del zócalo. ¿Aumentó el número de objetivos ping durante los últimos 15 años? Te estás preparando para una tormenta de respuesta de ping, y probablemente no leas esas respuestas lo suficientemente rápido, por lo que se acumulan en el búfer de recepción y, finalmente, se descartan.

Mis sugerencias con el fin de ROI:

  • extendió a cabo las solicitudes de ping, no se instale para un DDoS. Consulte, por ejemplo, un sistema por iteración y mantenga la última hora de verificación por objetivo. Esto le permitirá igualar el número de paquetes de entrada y salida.
  • Aumente SO_RCVBUF a un valor grande.Esto permitirá que su pila de red se ocupe mejor de las ráfagas de paquetes.
  • Lea los paquetes en un bucle, es decir, una vez que su socket UDP sea legible (suponiendo que no sea un bloqueo), lea hasta que obtenga EWOULDBLOCK. Esto le ahorrará un montón de llamadas select().
  • Vea si puede usar alguna API avanzada de Windows siguiendo las líneas de Linux recvmmsg(2), si tal cosa existe, para quitar múltiples paquetes por syscall.

Espero que esto ayude.

+0

En realidad, el zócalo estaba en modo de bloqueo, pero he tenido algunos registros que confirmaron que nunca tuve ese problema. En cuanto a los posibles DDOS, este problema ocurre en sistemas con 4 dispositivos y también en 20 (que es el sistema desplegado más grande que tenemos), así que no creo realmente que se trate de un DOS. Llevaré sus sugerencias al código y regresaré con los resultados. ¡Gracias! – flowInTheDark

+0

Hacer que el búfer sea más grande no ayudó, por extraño que parezca. Lo que sí ayudó al final fue su sugerencia de leer el socket en un bucle hasta EWOULDBLOCK cada vez que lo pueda leer. Ahora está funcionando como debería. ¡Gracias! – flowInTheDark

0

UDP no garantiza una transmisión confiable. Esto podría funcionar ahora, en la próxima hora y en el próximo año. Luego, en dos años, no podrá comunicarse durante una hora completa.

La ruta de ruta de los paquetes puede bloquearse en algunas situaciones. Cuando eso ocurre con TCP, se informa al remitente de la pérdida y el remitente puede intentar enviarla a través de una ruta de ruta diferente. Dado que UDP es un protocolo de transmisión de "enviar y olvidar", puede perder algunos de sus paquetes estadísticamente.

tl; dr Usa TCP.

+1

Observe la parte del texto donde menciono mi sniffing wireshark y confirmo que los paquetes realmente ingresaron al sistema. – flowInTheDark

Cuestiones relacionadas