2015-04-14 18 views
6

La domanda implicita è: se Linux blocca la chiamata send() quando il buffer di invio del socket è pieno, perché dovrebbero esserci dei pacchetti persi?In Linux, perché perdo i pacchetti UDP se chiamo send() il più velocemente possibile?

Ulteriori dettagli: Ho scritto una piccola utilità in C per inviare pacchetti UDP il più velocemente possibile a un indirizzo unicast e una porta. Invio un payload UDP di 1450 byte ogni volta e i primi byte sono un contatore che incrementa di 1 per ogni pacchetto. Lo eseguo su un Fedora 20 all'interno di VirtualBox su un PC desktop con un nicot da 1 Gb (= abbastanza lento).

Quindi ho scritto una piccola utilità per leggere i pacchetti UDP da una determinata porta che controlla il contatore del pacchetto contro il proprio contatore e stampa un messaggio se sono diversi (vale a dire 1 o più pacchetti sono stati persi). Lo eseguo su un server bi-xeon Fedora 20 con un ethernet nic da 1 Gb (= super veloce). Mostra molti pacchetti persi.

Entrambe le macchine sono su una rete locale. Non conosco esattamente il numero di hop tra di loro, ma non credo che ci siano più di 2 router tra di loro.

cose che ho provato:

  • aggiungere un ritardo dopo ogni send(). Se imposto un ritardo di 1 ms, non si perde più alcun pacchetto. Un ritardo di 100us inizierà a perdere pacchetti.
  • Aumentare la dimensione del buffer del socket di ricezione a 4MiB utilizzando setsockopt(). Questo non fa alcuna differenza ...

Per favore mi illumini!

+0

Non penso che questa sia davvero una domanda di programmazione. È un po 'torbido, però. – unwind

risposta

6

Per UDP l'opzione socket SO_SNDBUF limita solo la dimensione del datagramma che è possibile inviare. Non esiste una limitazione esplicita del buffer del socket di invio come con TCP. C'è, naturalmente, l'accodamento nel kernel dei frame sulla scheda di rete.

In altre parole, send(2) potrebbe eliminare il datagramma senza restituire un errore (controllare la descrizione di ENOBUFS nella parte inferiore della pagina di manuale).

Poi il pacchetto potrebbe essere eliminato praticamente ovunque sul percorso:

  • invio di scheda di rete non dispone di risorse hardware liberi per soddisfare la richiesta, frame viene scartato,
  • dispositivo di routing intermedio non ha a disposizione buffer space o implementa qualche algoritmo per evitare la congestione, elimina il pacchetto,
  • la ricezione della scheda di rete non può accettare frame ethernet a una determinata velocità, alcuni frame vengono semplicemente ignorati.
  • L'applicazione del lettore non ha abbastanza spazio per il buffer di ricezione socket per contenere i picchi di traffico, il kernel rilascia i datagrammi.

Da quello che hai detto, sembra molto probabile che la VM non sia in grado di inviare i pacchetti ad alta velocità. Annota il filo con tcpdump(1) o wireshark(1) il più vicino possibile alla fonte e controlla i numeri di sequenza, che ti diranno se è il mittente a incolpare.

+1

Grazie Nikolai. La pagina man afferma infatti che "i pacchetti vengono rilasciati silenziosamente quando una coda di dispositivo è in overflow". È molto probabile ciò che sta accadendo lì. Grazie per aver segnalato questo! – seeker

0
  • Qualsiasi dei due router si menzionate potrebbe eliminare i pacchetti se c'è un sovraccarico,
  • e il PC di ricezione potrebbe cadere o pacchetti perdere come pure in determinate circostanze, come sovraccarico.
2

Anche se send() blocchi quando il buffer di trasmissione è pieno (a condizione che non è stato impostato SOCK_NONBLOCK sul socket per metterlo in modalità non-blocking) il ricevitore deve essere ancora abbastanza veloce per gestire tutti i pacchetti in entrata. Se il ricevitore o qualsiasi sistema intermedio è più lento del mittente, i pacchetti andranno persi quando si utilizza UDP. Notare che più lento non si applica solo alla velocità dell'interfaccia di rete ma all'intero stack di rete più l'applicazione dello spazio utente.

Nel tuo caso è del tutto possibile che il ricevitore stia ricevendo tutti i pacchetti ma non li possa gestire abbastanza velocemente nello spazio utente. Puoi verificarlo registrando e analizzando il tuo traffico tramite tcpdump o wireshark.

Se non si desidera perdere i pacchetti, passare a TCP.

0

Come uno dei suddetti poster ha detto, UDP è un semplice protocollo datagramma che non garantisce la consegna. A causa della macchina locale, delle apparecchiature sulla rete, ecc. Questo è il motivo per cui molti sviluppatori attuali raccomandano, se si vuole affidabilità, passare a TCP. Tuttavia, se si vuole davvero attenersi al protocollo UDP e ci sono molti validi motivi per farlo, è necessario trovare una libreria che ti aiuti a garantire la consegna. Cerca i progetti SS7 soprattutto nelle API di telefonia dove UDP viene utilizzato per trasmettere informazioni vocali, dati e di segnalazione. Per la tua unica applicazione, posso suggerire la libreria UDP di enet. http://enet.bespin.org/

Problemi correlati