Czy pakiety TCP i UDP można podzielić na części?


41

Czy pakiety TCP mogą docierać do odbiornika na sztuki?

Na przykład, jeśli wysyłam 20 bajtów za pomocą protokołu TCP, czy mogę być w 100% pewien, że otrzymam dokładnie 20 bajtów naraz, a nie 10 bajtów, a następnie kolejne 10 bajtów?

I to samo pytanie dotyczące protokołu UDP.
Wiem, że UDP jest zawodny i pakiety nie mogą w ogóle dotrzeć lub przybyć w innej kolejności, ale co z pojedynczym pakietem? Jeśli nadejdzie, czy mogę być pewien, że jest to kompletny pakiet, a nie kawałek?


7
Wyjaśnienie: Nazywa się to segmentem TCP i datagramem UDP. Nie są to pakiety. TCP = segment, UDP = datagram, IP = pakiet, Ethernet = ramka, na wszystkich innych warstwach (AFAIK) nazywane są po prostu PDU (Jednostkami danych protokołu).
joeqwerty

Odpowiedzi:


33

czy pakiety TCP mogą docierać do odbiornika na sztuki?

Tak. Protokół IP obsługuje fragmentację, chociaż protokół TCP zazwyczaj próbuje ustalić ścieżkę MTU i zachować swoje pakiety mniejsze niż ten ze względu na wydajność. Fragmentacja katastrofalnie zwiększa wskaźnik utraty datagramów. Jeśli ścieżka ma współczynnik utraty pakietów wynoszący 10%, fragmentacja datagramu na dwa pakiety powoduje, że wskaźnik utraty datagramów wynosi prawie 20%. (Jeśli którykolwiek pakiet zostanie utracony, datagram zostanie utracony.)

Nie musisz się tym jednak martwić, podobnie jak warstwa TCP. Warstwa IP ponownie składa pakiety w całe datagramy.

Np .: jeśli wysyłam 20 bajtów za pomocą protokołu TCP, czy mogę być w 100% pewien, że otrzymam dokładnie 20 bajtów naraz, a nie 10 bajtów, a następnie kolejne 10 bajtów?

Nie, ale to nie ma nic wspólnego z pakietami. TCP jest zasadniczo protokołem strumienia bajtów, który nie zachowuje granic komunikatów aplikacji.

I to samo pytanie dotyczące protokołu UDP. Wiem, że UDP jest zawodny i pakiety nie mogą w ogóle dotrzeć lub przybyć w innej kolejności,

To samo dotyczy TCP. Pakiety to pakiety. Różnica polega na tym, że protokół TCP ma wbudowane w protokół próby i zmiany kolejności, podczas gdy protokół UDP nie.

ale co z 1 pakietem? Jeśli nadejdzie, czy mogę być pewien, że jest to kompletny pakiet, a nie kawałek?

Nie, ale to nie twój problem. Protokół UDP obsługuje ponowny montaż datagramu. To część jego pracy. (W rzeczywistości protokół IP robi to w przypadku protokołu UDP, więc UDP robi to po prostu warstwowo na szczycie IP). Jeśli datagram zostanie podzielony na dwa pakiety, protokół IP ponownie złoży go dla protokołu UDP, więc zobaczą pełne dane.


10
Być może warto wyjaśnić ostatni kawałek dla początkujących czytelników: zobaczysz pełne dane dla danego datagramu . Jeśli którykolwiek z podzielonych pakietów zostanie utracony, datagram zostanie utracony, a warstwa UDP nigdy się o nim nie dowie. Dopóki wszystkie pakiety w datagramie zostaną odebrane, będą one składane w warstwie IP, a następnie przekazywane do warstwy UDP. Nie wyklucza to możliwości pominięcia „fragmentów” w strumieniu danych. Nie chcę być pedantem, ale kiedy uczyłem się tego, nie zastanawiałem się nad różnicą między fragem IP a utratą UDP, dopóki druga lub trzecia część nie przejdzie przez podręcznik.
Justin ᚅᚔᚈᚄᚒᚔ

20

Nie możesz być pewien, że naprawdę fizycznie przybywają na raz. Warstwy łącza danych poniżej TCP / UDP mogą podzielić twój pakiet, jeśli chcą. Szczególnie, jeśli wysyłasz dane przez Internet lub dowolną sieć poza Twoją kontrolą, trudno to przewidzieć.

Ale bez względu na to, czy dane dotrą do jednego pakietu czy wielu pakietów do odbiornika. System operacyjny powinien wyodrębnić konkatenację tych pakietów, więc dla twojej aplikacji nadal wygląda na to, że wszystko dotarło na raz. Tak więc, chyba że jesteś hakerem jądra, w większości przypadków nie musisz się martwić, jeśli dane te zostaną przesłane w jednym lub wielu pakietach.

W przypadku UDP system operacyjny wykona również abstrakcję, więc aplikacja odbierająca dane nie musi wiedzieć, w ilu pakietach dane zostały przesłane. Różnica w stosunku do TCP polega na tym, że nie ma gwarancji, że dane faktycznie dotrą. Możliwe jest również, że dane zostaną podzielone na wiele pakietów, a niektóre z nich dotrą, a niektóre nie. W przypadku aplikacji odbierającej i tak wygląda to jak strumień danych, bez względu na to, czy jest kompletny, czy nie.


Czy sterownik karty sieciowej nie zajmuje się ponownym składaniem pakietów, a nie jądrem?
bluehallu

2
@Hallucynogenyc: O ile nic się nie zmieni, protokół internetowy został zaprojektowany w taki sposób, aby umożliwić podział pakietów o długości ponad 576 bajtów w dowolnym momencie ich podróży, ale nie oczekuje od odbiorcy końcowego ich rekombinacji. Myślę, że chodzi o to, że użycie większych pakietów było w większości przypadków próbą zmniejszenia narzutu; gdy pakiet zostanie podzielony w pewnym momencie podróży, koszty ogólne zostały już poniesione, więc rekombinacja, zanim ostateczny odbiorca nie będzie w stanie nic pomóc i może zaszkodzić, jeśli będzie musiał zostać ponownie podzielony.
supercat

Uważam, że chociaż każdy pakiet, który ma ponad 576 bajtów, może być podzielony, pakiety poniżej tego rozmiaru mogą nie być podzielone; systemy wbudowane, które nie radzą sobie z dzielonymi pakietami, powinny unikać proszenia o coś większego niż to.
supercat

1
@ mauro.stettler: Napisałem stos TCP na „bare metal” (piszę kod, aby rozmawiać bezpośrednio z wieloma układami interfejsu sieciowego). Dla sprzętu, który komunikuje się z łączem o limicie 576 bajtów, dzielenie dłuższych pakietów jest proste. Ponowne składanie pakietów jest znacznie bardziej skomplikowane, tym bardziej, że można otrzymać wiele różnych pakietów, zanim którykolwiek z nich zostanie odebrany w całości.
supercat

Istnieje nadzieja, że ​​nie zostanie podzielony na małe ładunki (około 10 lub 20 bajtów powinno być w porządku), ponieważ istnieje „gwarantowany maksymalny rozmiar” każdego skoku dla pakietów IP na ipv4: co najmniej 68 bajtów (w tym Nagłówki IP, nie licząc nagłówków niższego poziomu). patrz 1. tabela w en.wikipedia.org/wiki/Maximum_transmission_unit . Różni się od 576 bajtów minimalnego rozmiaru wymaganych od HOSTS (tj. Początek lub koniec transmisji, nie wszystkie pośrednie przeskoki). I ostrożnie: ładowność jest jeszcze niższa (ponieważ nagłówki każdej warstwy zajmują trochę miejsca).
Olivier Dulac

14

Przykłady Bloki ciągłych znaków odpowiadają wywołaniom send ():

TCP:

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

Wszystkie przesyłane dane są odbierane w kolejności, ale niekoniecznie w tych samych częściach.

UDP:

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

Dane niekoniecznie są w tej samej kolejności i wcale niekoniecznie są odbierane, ale wiadomości są zachowywane w całości.


5

Np .: jeśli wysyłam 20 bajtów za pomocą protokołu TCP, czy mogę być w 100% pewien, że otrzymam dokładnie 20 bajtów naraz, a nie 10 bajtów, a następnie kolejne 10 bajtów?

Nie, TCP jest protokołem strumieniowym, utrzymuje dane w porządku, ale nie grupuje ich według wiadomości. Z drugiej strony UDP jest zorientowany na wiadomości, ale zawodny. SCTP ma to, co najlepsze z obu światów, ale nie można go używać natywnie, ponieważ translatory NAT niszczą Internet.


1

Istnieje pewna pewność, że jeśli wyślesz 20 bajtów na samym początku strumienia TCP, nie pojawi się on jako dwa 10 bajtów. Wynika to z faktu, że stos TCP nie wysyła tak małych segmentów: istnieje minimalny rozmiar MTU. Jeśli jednak wysyłanie znajduje się gdziekolwiek w środku strumienia, wszystkie zakłady są wyłączone. Może być tak, że stos protokołu zajmuje 10 bajtów danych, aby wypełnić segment i wysłać go, a następnie następne dziesięć bajtów przechodzi do innego segmentu.

Stos protokołu dzieli dane na części i umieszcza je w kolejce. Rozmiary porcji są oparte na MTU ścieżki. Jeśli wykonasz operację wysyłania i nadal oczekują na dane w kolejce, stos protokołów zwykle zerknie na segment znajdujący się na końcu kolejki i sprawdzi, czy w tym segmencie jest miejsce na dodanie kolejnych danych. Pokój może być tak mały jak jeden bajt, więc nawet dwubajtowe wysyłanie może zostać podzielone na dwa.

Z drugiej strony segmentacja danych oznacza, że ​​mogą być częściowe odczyty. Operacja odbierania może potencjalnie obudzić się i uzyskać dane, gdy pojawi się zaledwie jeden segment. W szeroko zaimplementowanym interfejsie API gniazd, wywołanie odbierające może poprosić o 20 bajtów, ale może zwrócić z wartością 10. Oczywiście można na nim zbudować warstwę buforującą, która będzie blokować do momentu odebrania 20 bajtów lub przerwania połączenia. W świecie POSIX ten interfejs API może być standardowym strumieniem we / wy: możesz użyć fdopendeskryptora gniazda, aby uzyskać FILE *strumień, i możesz freadna nim użyć do wypełnienia bufora, aby pełne żądanie było zadowolone z tylu readwywołań, ile potrzeba .

Datagramy UDP tworzą ramkę danych. Każde połączenie wysyłające generuje datagram (ale patrz poniżej o korkowaniu). Druga strona otrzymuje pełny datagram (i w interfejsie API gniazda musi określić bufor wystarczająco duży, aby go pomieścić, w przeciwnym razie datagram zostanie obcięty). Duże datagramy są pofragmentowane przez fragmentację adresów IP i są ponownie składane w przejrzysty sposób dla aplikacji. Jeśli brakuje jakiegoś fragmentu, cały datagram zostaje utracony; w takiej sytuacji nie można odczytać częściowych danych.

Istnieją rozszerzenia interfejsu umożliwiające wielu operacjom określenie jednego datagramu. W systemie Linux gniazdo można „zakorkować” (uniemożliwić wysyłanie). Podczas gdy jest zakorkowany, zapisane dane są składane w jedną całość. Następnie, gdy gniazdo jest „odkorkowane”, można wysłać pojedynczy datagram.


jest to nieprawda: jeśli wyślesz paquet z 10 lub 20 bajtowym ładunkiem, wygeneruje to 1 paquet i (jak powiedziałem powyżej), jeśli używasz ipv4, powinien, nawet po dodaniu wszystkich nagłówków innych warstw protokołu, dopasować do 68 bajtów, co zapewnia przejście przez wszystkie przeskoki w 1 pakiecie. Stos Tcp nie będzie (jak wskazano w pierwszym akapicie) „czekać, aż mtu zostanie wypełnione (tj. Dodać kilka pakietów, aby utworzyć odpowiedni rozmiar)”, aby wysłać pakiet! ... Takie zachowanie zepsułoby wiele rzeczy ( nawet jeśli te „fragmenty” zostały wysłane z i do tej samej pary hostów)
Olivier Dulac

@OlivierDulac: To jest nieprawidłowe. TCP zwykle generuje pakiety zgodnie z potrzebami, próbując zoptymalizować wykorzystanie sieci, więc 20 bajtów może skończyć w dwóch różnych pakietach, jak wyjaśnia Kaz. Można to kontrolować za pomocą opcji gniazda TCP_NODELAY , która wyłącza algorytm Nagles, który wysyła bajty do pakietów, jeśli aplikacja potrzebuje szybszej sieci TCP. Ponadto 68 bajtów nie jest de facto standardem dla długości pakietów: 1500 bajtów jest bardziej typową wartością domyślną (tak naprawdę różni się w zależności od sieci).
jjmontes
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.