I pacchetti TCP e UDP possono essere suddivisi in pezzi?


41

I pacchetti TCP possono arrivare al destinatario per pezzi?

Ad esempio, se invio 20 byte utilizzando il protocollo TCP, posso essere sicuro al 100% di ricevere esattamente 20 byte contemporaneamente, non 10 byte e altri 10 byte circa?

E la stessa domanda per il protocollo UDP.
So che UDP non è affidabile e che i pacchetti non possono arrivare o arrivare in un ordine diverso, ma che dire di un singolo pacchetto? Se arriva, posso essere sicuro che sia un pacchetto completo, non un pezzo?


7
Un punto di chiarimento: si chiama segmento TCP e datagramma UDP. Non sono pacchetti. TCP = Segmento, UDP = Datagramma, IP = Pacchetto, Ethernet = Frame, A tutti gli altri livelli (AFAIK) sono chiamati semplicemente PDU (Protocol Data Unit).
joeqwerty,

Risposte:


33

i pacchetti TCP possono arrivare al destinatario per pezzi?

Sì. L'IP supporta la frammentazione, sebbene TCP generalmente cerchi di determinare il percorso MTU e mantenere i suoi pacchetti più piccoli di quello per motivi di prestazioni. La frammentazione aumenta catastroficamente il tasso di perdita del datagramma. Se un percorso ha un tasso di perdita dei pacchetti del 10%, la frammentazione di un datagramma in due pacchetti rende il tasso di perdita del datagramma quasi del 20%. (Se uno dei pacchetti viene perso, il datagramma viene perso.)

Non devi preoccuparti di questo, e nemmeno il livello TCP. Il livello IP riassembla i pacchetti in interi datagrammi.

Ad esempio: se invio 20 byte utilizzando il protocollo TCP, posso essere sicuro al 100% di ricevere esattamente 20 byte contemporaneamente, non 10 byte e altri 10 byte circa?

No, ma ciò non ha nulla a che fare con i pacchetti. TCP è fondamentalmente un protocollo di flusso di byte che non preserva i confini dei messaggi dell'applicazione.

E la stessa domanda per il protocollo UDP. So che UDP non è affidabile e i pacchetti non possono arrivare o arrivare in un ordine diverso,

Lo stesso vale per TCP. I pacchetti sono pacchetti. La differenza è che TCP ha tentativi e riordini integrati nel protocollo mentre UDP no.

ma che dire di 1 pacchetto? Se arriva, posso essere sicuro che sia un pacchetto completo, non un pezzo?

No, ma non è questo il tuo problema. Il protocollo UDP gestisce il rimontaggio del datagramma. Fa parte del suo lavoro. (In realtà, il protocollo IP lo fa per il protocollo UDP, quindi UDP lo fa semplicemente sovrapponendosi all'IP.) Se un datagramma viene suddiviso su due pacchetti, il protocollo IP lo riassemblerà per il protocollo UDP, quindi tu vedrà i dati completi.


10
Potrebbe valere la pena di chiarire l'ultimo bit per i lettori alle prime armi: vedrai i dati completi per il datagramma in questione . Se uno qualsiasi dei pacchetti divisi viene perso, il datagramma viene perso e il livello UDP non lo saprà mai. Finché tutti i pacchetti nel datagramma vengono ricevuti, verranno assemblati a livello IP e quindi passati al livello UDP. Ciò non preclude la possibilità di perdere "blocchi" nel flusso di dati. Non per essere un pedante, ma quando stavo imparando queste cose non ho notato la differenza tra frammento IP e perdita UDP fino a quando il 2 ° o il 3 ° passaggio del libro di testo.
Justin ᚅᚔᚈᚄᚒᚔ

20

Non puoi essere sicuro che arrivino davvero fisicamente in una volta. I livelli di collegamento dati sotto TCP / UDP potrebbero dividere il pacchetto se lo desiderano. Soprattutto se si inviano dati su Internet o su qualsiasi rete al di fuori del proprio controllo, è difficile prevederlo.

Ma non importa se i dati arrivano in un pacchetto o più pacchetti al destinatario. Il sistema operativo dovrebbe astrarre la concatenazione di questi pacchetti, quindi per la tua applicazione sembra che tutto sia arrivato in una volta. Quindi, a meno che tu non sia un hacker del kernel, nella maggior parte dei casi non devi preoccuparti se questi dati vengono trasferiti in uno o più pacchetti.

Per UDP il sistema operativo farà anche qualche astrazione, quindi l'applicazione che riceve i dati non deve sapere in quanti pacchetti i dati sono stati trasmessi. Ma la differenza con TCP è che non esiste alcuna garanzia che i dati arrivino effettivamente. È anche possibile che i dati vengano suddivisi in più pacchetti e alcuni arrivano e altri no. Per l'applicazione ricevente sembra comunque un flusso di dati, indipendentemente dal fatto che sia completo o meno.


Il driver della scheda di rete non si occupa di riassemblare i pacchetti non il kernel?
bluehallu,

2
@Hallucynogenyc: a meno che le cose non cambino, il protocollo Internet è progettato per consentire la suddivisione dei pacchetti di oltre 576 byte in qualsiasi momento del loro viaggio, ma non si aspetta che il destinatario finale li ricombini. Penso che l'idea sia che l'uso di pacchetti più grandi sia stato nella maggior parte dei casi uno sforzo per ridurre le spese generali; una volta che un pacchetto è stato diviso ad un certo punto del suo viaggio, l'overhead è già stato sostenuto in modo tale da ricombinarsi prima che il destinatario finale non sia in grado di aiutare nulla e possa ferire se deve essere suddiviso.
supercat

Credo che mentre qualsiasi pacchetto che supera i 576 byte può essere suddiviso, i pacchetti che sono al di sotto di quella dimensione non possono farlo; i sistemi embedded che non possono gestire pacchetti divisi dovrebbero evitare di chiedere qualcosa di più grande di quello.
Supercat,

1
@ mauro.stettler: ho scritto uno stack TCP su "bare metal" (scrivendo il codice per parlare direttamente con un numero di chip di interfaccia di rete). Per l'hardware che comunica con un collegamento con un limite di 576 byte per dividere i pacchetti più lunghi è semplice. Il riassemblaggio dei pacchetti è molto più complicato, soprattutto perché si possono ricevere pezzi di molti pacchetti diversi prima che uno di essi venga ricevuto per intero.
supercat

C'è qualche speranza che non venga suddiviso per piccoli payload (circa 10 o 20 byte dovrebbero essere ok), perché è richiesta una "dimensione massima garantita" per ogni hop per i paquets IP su ipv4: almeno 68 byte (incluso Intestazioni IP e senza contare le intestazioni di livello inferiore). vedere la prima tabella in en.wikipedia.org/wiki/Maximum_transmission_unit . Diverso dai 576 byte di dimensioni minime richieste dagli HOSTS (ovvero, l'origine o la fine della trasmissione, non tutti i salti intermedi). E attento: il payload è ancora più basso (poiché le intestazioni di ogni livello occupano spazio).
Olivier Dulac,

14

Esempi. I blocchi di caratteri contigui corrispondono alle chiamate send ():

TCP:

Send: AA BBBB CCC DDDDDD E         Recv: A ABB B BCC CDDD DDDE

Tutti i dati inviati vengono ricevuti in ordine, ma non necessariamente negli stessi blocchi.

UDP:

Send: AA BBBB CCC DDDDDD E         Recv: CCC AA E

I dati non sono necessariamente nello stesso ordine e non sono necessariamente ricevuti, ma i messaggi sono conservati nella loro interezza.


5

Ad esempio: se invio 20 byte utilizzando il protocollo TCP, posso essere sicuro al 100% di ricevere esattamente 20 byte contemporaneamente, non 10 byte e altri 10 byte circa?

No, TCP è un protocollo stream, mantiene i dati in ordine ma non li raggruppa per messaggio. D'altra parte UDP è orientato ai messaggi, ma inaffidabile. SCTP ha il meglio dei due mondi ma non è utilizzabile in modo nativo perché i NAT rompono Internet.


1

C'è una certa certezza che se si inviano 20 byte all'inizio di un flusso TCP, non arriveranno come due pezzi da 10 byte. Questo perché lo stack TCP non invierà segmenti così piccoli: esiste una dimensione MTU minima. Tuttavia, se l'invio è ovunque nel mezzo di uno stream, tutte le scommesse sono disattivate. È possibile che lo stack del protocollo impieghi 10 byte di dati per riempire un segmento e inviarlo, quindi i successivi dieci byte vanno a un altro segmento.

Lo stack del protocollo suddivide i dati in blocchi e li inserisce in una coda. Le dimensioni del blocco si basano sul percorso MTU. Se si esegue un'operazione di invio e sono ancora presenti dati in coda in sospeso, lo stack del protocollo in genere sbircia il segmento che si trova in coda alla coda e vedrà se c'è spazio in quel segmento per aggiungere altri dati. La stanza potrebbe essere piccola come un byte, quindi anche un invio a due byte potrebbe essere suddiviso in due.

Dall'altro lato, la segmentazione dei dati significa che possono esserci letture parziali. Un'operazione di ricezione può potenzialmente riattivare e ottenere dati quando arriva solo un segmento. Nell'API socket ampiamente implementata, una chiamata in ricezione può richiedere 20 byte, ma potrebbe restituire con 10. Naturalmente, è possibile creare un livello di buffer su di esso che si bloccherà fino a quando non vengono ricevuti 20 byte o la connessione si interrompe. Nel mondo POSIX, quell'API può essere lo stream I / O standard: è possibile fdopenun descrittore di socket per ottenere uno FILE *stream e si può usare freadsu di esso per riempire un buffer in modo tale che la richiesta completa sia soddisfatta da tutte le readchiamate necessarie .

I datagrammi UDP inquadrano i dati. Ogni chiamata di invio genera un datagramma (ma vedi sotto sulla tappatura). L'altro lato riceve un datagramma completo (e, nell'API socket, deve specificare un buffer abbastanza grande da mantenerlo, altrimenti il ​​datagramma verrà troncato). Datagrammi di grandi dimensioni vengono frammentati dalla frammentazione IP e vengono riassemblati in modo trasparente per le applicazioni. Se manca qualche frammento, l'intero datagramma viene perso; non c'è modo di leggere dati parziali in quella situazione.

Esistono estensioni all'interfaccia che consentono a più operazioni di specificare un singolo datagramma. In Linux, un socket può essere "tappato" (impedito l'invio). Mentre viene tappato, i dati scritti vengono assemblati in una singola unità. Quindi quando il socket viene "stappato", è possibile inviare un singolo datagramma.


questo è falso: se si invia un paquet con un payload di 10 o 20 byte, questo genererà 1 paquet e (come ho detto sopra), se si utilizza ipv4, dovrebbe, anche quando si aggiungono tutte le intestazioni degli altri layer del protocollo, adattarsi entro 68 byte, garantendo così che attraversi tutti i salti in 1 pacchetto. Lo stack TCC non (come è accennato nel tuo primo paragrafo) "aspetta che il mtu sia pieno (cioè, aggiungi diversi pacchetti per crearne uno di dimensioni adeguate)" per inviare un pacchetto! ... Questo comportamento romperebbe molte cose ( anche se quei "frammenti" sono stati inviati da e alla stessa coppia di host)
Olivier Dulac,

@OlivierDulac: non è corretto. TCP di solito genera pacchetti di cui ha bisogno, cercando di ottimizzare l'utilizzo della rete, quindi 20 byte potrebbero finire in due pacchetti diversi, come spiegato da Kaz. Questo può essere controllato usando l' opzione socket TCP_NODELAY , che disabilita l'algoritmo Nagles che invia byte ai pacchetti, se l'applicazione richiede una rete TCP più veloce. Inoltre, 68 byte non è affatto lo standard di fatto per la lunghezza dei pacchetti: 1500 byte è un valore predefinito più comune (questo varia davvero tra le reti).
Jjmontes,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.