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?
networking
tcp
udp
iamnp
źródło
źródło
Odpowiedzi:
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.
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.
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.
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.
źródło
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.
źródło
Przykłady Bloki ciągłych znaków odpowiadają wywołaniom send ():
TCP:
Wszystkie przesyłane dane są odbierane w kolejności, ale niekoniecznie w tych samych częściach.
UDP:
Dane niekoniecznie są w tej samej kolejności i wcale niekoniecznie są odbierane, ale wiadomości są zachowywane w całości.
źródło
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.
źródło
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ć
fdopen
deskryptora gniazda, aby uzyskaćFILE *
strumień, i możeszfread
na nim użyć do wypełnienia bufora, aby pełne żądanie było zadowolone z tyluread
wywoł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.
źródło