Python socket en bruto que escucha paquetes UDP; solo la mitad de los paquetes recibidos

Estoy intentando crear un socket sin procesar en Python que solo escucha los paquetes UDP:

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 debe ejecutarse como root y crea un socket sin procesar en el puerto 1337, que escucha los paquetes UDP y los imprime cada vez que se reciben; No hay problemas allí.

Ahora hagamos un pequeño 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, solo el primer, tercer y quinto mensaje ( message 1 , message 3 y message 5 ) se enviarán y se imprimirán en la salida del servidor. Los mensajes 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 "", line 1, in  socket.error: [Errno 111] Connection refused 

Ejecutar esto en Wireshark muestra que se está recibiendo una respuesta ICMP para “Destino inalcanzable”. He podido reproducir esto en 3 máquinas distintas (aunque todas ejecutan Linux). ¿Me estoy perdiendo de algo? ¿Es este comportamiento esperado para que UDP elimine paquetes constantemente, ya que se supone que los protocolos que lo usan toleran la pérdida de paquetes? Aun así, ¿por qué se eliminan los paquetes cuando se envían a la interfaz local?

Vincular el servidor a 127.0.0.1 lugar de 0.0.0.0 tiene el mismo resultado.

Resuelto de una manera un poco tonta; por favor, avíseme si hay otra manera, y cambiaré la respuesta aceptada.

La solución es simplemente usar dos sockets enlazados en el mismo puerto; uno crudo, uno no crudo

 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 los paquetes ICMP de “Destino inalcanzable” desaparezcan y que todos los paquetes pasen bien. Creo que el sistema operativo quiere que un socket que no esté en bruto escuche en el puerto para que las cosas vayan bien, y luego que cualquier socket en bruto que escuche en ese mismo puerto recibirá copias de los paquetes.