2012-04-01 18 views
7

Sto cercando di creare un grezzo presa in Python che attende solo i pacchetti UDP:socket raw Python in ascolto per pacchetti UDP; solo la metà dei pacchetti ricevuti

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) 

Ciò deve essere eseguito come root, e crea un raw socket sulla porta 1337 , che ascolta i pacchetti UDP e li stampa ogni volta che vengono ricevuti; nessun problema lì.

Ora facciamo un piccolo client per verificare se questo funziona:

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') 

Coerentemente, solo il primo, il terzo e il quinto messaggio (message 1, message 3 e message 5) otterrà attraverso ed essere stampato nel server produzione. Il secondo, il quarto e il sesto messaggi non si presentano in uscita del server, e invece il cliente ottiene un'eccezione:

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

L'esecuzione di questo in Wireshark mostra che sta ottenendo una risposta ICMP per "Destinazione irraggiungibile". Sono stato in grado di riprodurlo su 3 macchine distinte (tutte però con Linux in esecuzione). Mi sto perdendo qualcosa? Questo comportamento previsto per UDP è quello di eliminare costantemente i pacchetti, dal momento che i protocolli che lo utilizzano dovrebbero tollerare la perdita di pacchetti? Anche così, perché i pacchetti dovrebbero essere eliminati quando vengono inviati sull'interfaccia locale?

Il collegamento del server a 127.0.0.1 anziché lo 0.0.0.0 ha lo stesso risultato.

+0

A volte accadono cose strane con lo stack di messaggi. L'adattatore ethernet in questo caso utilizza il loopback, ma ancora, i pacchetti "phsically" continuano ancora sulla scheda e poi vengono interpretati dal driver su come ordinare la coda dei messaggi. solo alcuni punti di ricerca per dare una mano. – FlavorScape

+0

@Etienne, FlavorScape Ricevo l'errore ogni altro pacchetto, che sembra troppo regolare per essere un errore di rete ... – brice

+0

Sì, succede ogni due pacchetti, il che significa che se si inviano pacchetti '2 * n', tutti i pacchetti di la forma '2 * i + 1' non passerà. Non penso che questo possa essere una perdita di pacchetti, poiché questo è tutto nell'interfaccia locale. –

risposta

7

Risolto in modo un po 'sciocco; per favore fatemi sapere se c'è un altro modo, e cambierò la risposta accettata.

La soluzione consiste semplicemente nell'utilizzare due socket associati sulla stessa porta; uno grezzo, non 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) 

Questo rende i "irraggiungibili" Destination pacchetti ICMP andare via e rende tutti i pacchetti passano bene. Penso che il sistema operativo voglia un socket non raw in ascolto sulla porta affinché le cose vadano bene, e quindi qualsiasi socket raw in ascolto su quella stessa porta riceverà copie dei pacchetti.

+0

interessante, che è davvero carino da sapere! – brice

+0

Questo era esattamente quello che stavo cercando! (tuttavia per Windows che richiede l'inizializzazione del socket RAW leggermente diverso) –

Problemi correlati