2010-03-30 14 views
7

Utilizzando le API socket UNIX su Linux, esiste un modo per garantire di leggere un pacchetto UDP e un solo pacchetto UDP? Attualmente sto leggendo pacchetti da un socket non bloccante usando recvmsg, con una dimensione del buffer un po 'più grande della MTU della nostra rete interna. Ciò dovrebbe garantire che possa sempre ricevere il pacchetto UDP completo, ma non sono sicuro di poter garantire che non riceverò mai più di un pacchetto per ogni chiamata recvmsg, se i pacchetti sono piccoli.posso leggere esattamente un pacchetto UDP da un socket?

Le pagine man di riferimento richiamano l'opzione MSG_WAITALL, che tenta di attendere fino al riempimento del buffer. Non stiamo usando questo, quindi implica che recvmsg ritornerà sempre dopo che un datagramma è stato letto? C'è un modo per garantire questo?

Idealmente mi piacerebbe una soluzione cross UNIX, ma se questo non esiste c'è qualcosa di specifico per Linux?

+1

MSG_WAITALL è per socket orientati al flusso: http://linux.die.net/man/3/recvmsg Come già risposto, recv/send() funziona utilizzando interi datagrammi per socket orientati al datagramma. – Ioan

risposta

12

recvmsg restituirà un pacchetto e sarà l'intero pacchetto (purché il buffer fornito sia sufficientemente grande).

Da the POSIX documentation:

La funzione recvmsg() deve ricevere un messaggio da un collegamento-mode o zoccolo connessione in modalità.

"un messaggio" significa esattamente un messaggio (o pacchetto), e,

Per socket basati sui messaggi, come SOCK_DGRAM e SOCK_SEQPACKET, l'intero messaggio si leggono in una singola operazione.

+0

Se c'è frammentazione. '' 'Recievemsg''' restituisce i dati solo dopo che l'intero pacchetto è stato ricostruito? – Artium

+0

Artium: Sì, questo viene eseguito dal sistema operativo e lo spazio utente vedrà solo i pacchetti assemblati e non i frammenti. Ciò significa che un pacchetto frammentato ricevuto sarà trattenuto dal sistema operativo per un po 'di tempo in attesa del resto dei frammenti. –

0

Un'opzione (dico opzione) è quella di utilizzare pcap_next utilizzando libpcap e prenderlo in considerazione per vedere se si tratta di un pacchetto udp. Si può fare questo con:

/* jump pass the ethernet header */ 
ipdata = (struct ip*)(packet + sizeof(struct ether_header)); 
length -= sizeof(struct ether_header); 

(Borrowed da tcpdump)

e quindi verificare la struct ip per vedere se si tratta di un pacchetto UDP facendo:

if (ipdata->ip_p == IPPROTO_UDP) 

E se questo non riesce , continua il ciclo (chiamando pcap_next) fino a quando non ottieni il tuo pacchetto udp. Ovviamente, l'estrazione del datagramma di udp è più difficile in questo modo, ma consente di inserire gli interni del pacchetto in modo abbastanza piacevole. Fare riferimento alla sorgente tcpdump per vedere come eliminare informazioni e cosa viene fuori.

Problemi correlati