2012-04-01 24 views
7

estoy tratando de crear un conector directo en Python que detecta solamente los paquetes UDP:Conector en bruto de Python que escucha paquetes UDP; sólo la mitad de los paquetes recibidos

import socket 
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP) 
s.bind(('0.0.0.0', 1337)) 
while True: 
    print s.recvfrom(65535) 

Esto tiene que ser ejecutado como root, y crea un conector directo en el puerto 1337 , que escucha los paquetes UDP y los imprime cada vez que se reciben; no hay problemas allí.

Ahora vamos a hacer un poco de cliente para probar si esto funciona:

import socket 
c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
c.connect(('127.0.0.1', 1337)) 
c.send('message 1') 
c.send('message 2') 
c.send('message 3') 
c.send('message 4') 
c.send('message 5') 
c.send('message 6') 

Consistentemente, sólo el primero, tercero y quinto mensaje (message 1, message 3 y message 5) obtendrá a través y ser impreso en el servidor salida. Los mensajes de segundo, cuarto y sexto no aparecen en la salida del servidor, y en cambio el cliente obtiene una excepción:

>>> c.send('message 2') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
socket.error: [Errno 111] Connection refused 

La ejecución de este en Wireshark muestra que se está haciendo una respuesta ICMP de "destino inaccesible". Pude reproducir esto en 3 máquinas distintas (aunque todas ejecutan Linux). ¿Me estoy perdiendo de algo? ¿Se espera que este comportamiento esperado para UDP caiga paquetes, ya que se supone que los protocolos que lo usan son tolerantes a la pérdida de paquetes? Aún así, ¿por qué se descartan los paquetes cuando se envían en la interfaz local?

Enlazando el servidor a 127.0.0.1 en lugar de 0.0.0.0 tiene el mismo resultado.

+0

A veces suceden cosas extrañas con la pila de mensajes. El adaptador de ethernet en este caso usa loopback, pero aún así, los paquetes "phsically" continúan en la tarjeta y luego son interpretados por el controlador en cuanto a cómo ordenar la cola de mensajes. solo algunos puntos de investigación para ayudar. – FlavorScape

+0

@Etienne, FlavorScape Recibo el error cada dos paquetes, que parece demasiado regular como para ser un error de red ... – brice

+0

Sí, sucede cada dos paquetes, lo que significa que si envía '2 * n' paquetes, todos los paquetes de la forma '2 * i + 1' no pasará. No creo que esto pueda ser una pérdida de paquetes, ya que todo está en la interfaz local. –

Respuesta

7

Lo resolvió de una manera tonta; por favor, avíseme si hay otra manera, y cambiaré la respuesta aceptada.

La solución es simplemente usar dos sockets vinculados en el mismo puerto; una prima, no se prima:

import socket, select 
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
s1.bind(('0.0.0.0', 1337)) 
s2 = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP) 
s2.bind(('0.0.0.0', 1337)) 
while True: 
    r, w, x = select.select([s1, s2], [], []) 
    for i in r: 
     print i, i.recvfrom(131072) 

Esto hace que el "destino inaccesible" paquetes ICMP desaparecen y hace que todos los paquetes que pasan a través de bien. Creo que el sistema operativo quiere un socket sin formato que escuche en el puerto para que las cosas funcionen bien, y luego cualquier socket en bruto que escuche en ese mismo puerto recibirá copias de los paquetes.

+0

interesante, ¡de hecho es bastante bueno saberlo! – brice

+0

¡Esto era exactamente lo que estaba buscando! (sin embargo, para Windows que requiere una inicialización de socket RAW ligeramente diferente) –

Cuestiones relacionadas