jeśli pakiet TCP zostanie częściowo potwierdzony, jak zareaguje mechanizm retransmisji?

12

jeśli klient tcp wyśle ​​pakiet o numerze sekwencyjnym od 10000 do 20000, na serwer tcp. tcp odpowie ACK za pomocą seq_ack 20001.

jeśli przechwycę pakiet TCP od klienta i podzielę pakiet na 2 segmenty TCP, jeden z sekwencją od 10000 do 15000, a drugi z sekwencją od 15001 do 20000. A następnie te 2 segmenty TCP zostaną wysłane do serwera TCP. Załóżmy, że drugi segment ginie na ścieżce. Serwer TCP odpowie ACK na seq_ack 15001.

Teraz, ponieważ klient TCP wysyła pakiet integralny o sekwencji od 10000 do 20000, ale otrzymuje ACK z 15001, z punktu widzenia klienta jest to dziwne. Jak to zareaguje? Teoretycznie klient powinien ponownie przesłać bajty z sekwencji 15001 do 20000, a mianowicie, klient wyśle ​​nowe pakiety z sekwencji 15001. Ale co z praktyką w implementacji stosu TCP, czy jest to to samo, co w teorii?

Myślę, że w buforze wysyłania TCP, gdy segment tcp jest wysyłany, segment pozostaje tam aż do potwierdzenia. Kiedy przychodzi ACK, bajty dla segmentu są usuwane z bufora. W buforze wysyłania znajduje się wskaźnik, gdy przychodzi potwierdzenie, wskaźnik wskazuje miejsce, w którym odpowiada parametr ack_seq. Bajty znajdujące się poniżej ack_seq są usuwane. W ten sposób cały segment nie musi być retransmitowany?

tajemnice
źródło

Odpowiedzi:

8

Nazywa się to selektywnym potwierdzaniem i jest już zawarte w specyfikacji TCP zdefiniowanej w RFC 2018 . Pozwoliłoby to klientowi na ponowne przesłanie tylko bajtów od 15001 do 20000 (ponieważ są one w różnych pakietach / segmentach, jeśli je podzieliłeś, jak mówisz), ale co bardziej interesujące, pozwala nawet na potwierdzenia braku zamówienia.

Od RFC 2018:

Po otrzymaniu ACK zawierającego opcję SACK nadawca danych POWINIEN zapisać selektywne potwierdzenie do wykorzystania w przyszłości. Zakłada się, że nadawca danych ma kolejkę retransmisji, która zawiera segmenty, które zostały przesłane, ale jeszcze nie potwierdzone, w kolejności numerów sekwencji.

Obsługa nieSACK jest wymagana przez specyfikację TCP. Jeśli klient lub serwer nie obsługuje selektywnego potwierdzenia, rzeczywiście wszystkie bajty od 10000 do 20000 musiałyby zostać ponownie przesłane.

Czy w implementacji stosu TCP jest tak samo jak w teorii?

Zwykle SACK jest obsługiwany, ponieważ wydajność, wydajność i opóźnienia są znaczące - szczególnie w sieci takiej jak Internet.

Rzeczywiście jednak te założenia powinny się spełnić, nawet jeśli ręcznie manipulujesz pakietami, jak już powiedziałeś. Zgodnie z RFC 793 , co najmniej, cały okno dane będą musiały być retransmitowane, ale odbiornik musi wiedzieć, że otrzymaliśmy dane jest co najmniej ważna . Aby uzyskać szczegółowe informacje na temat implementacji, sekcja 3.3 - Numery sekwencji z RFC 793.

Aby uzyskać zarys całego procesu zarówno z obsługą selektywnego potwierdzania, jak i bez niego, zobacz ten artykuł (który zawiera kilka bardzo przydatnych diagramów).

Przełom
źródło
jest to dla mnie trochę dziwne, ponieważ TCP jest protokołem zorientowanym na strumień, zorientowanym na bajty. Dlaczego powinien retransmitować cały segment? Wydaje mi się, że TCP bez SAKC jest protokołem strumieniowym zorientowanym na segmenty, ale TCP z Sack jest zorientowany na bajty. Wydaje mi się, że RFC nie opracowuje w tym zakresie specjalnie.
mysteryes
jak stos TCP zarządza swoim buforem wysyłania, czy jest taki sam, jak napisałem w zaktualizowanym pytaniu?
mysteryes
@misteryes W tym artykule opisano proces (z kilkoma świetnymi diagramami!).
Przełom
W poleconym przez ciebie linku wydaje się, że autor nadal omawia problem w sposób segmentowy, a nie w sposób bajtowy. Czyż nie
mysteryes
1
Znałem SACK, zanim opublikowałem to pytanie. Na samym początku nie sądzę, aby SACK miał coś wspólnego z tym pytaniem. Moim zdaniem, jeśli TCP nie jest zorientowany na bajty, ale zorientowany na segmenty, wówczas SACK powinien być taki sam. Różnica między włączoną funkcją SACK a wyłączoną funkcją SACK polega na tym, że w przypadku SACK TCP pozwala na dziurę w sekwencji w ack_seq. Ale myślałem, że dziura sekwencji odpowiada segmentowi. podczas gdy według twojego powiedzenia, dziura może stanowić połowę / część segmentu.
mysteryes
3

Rozmiary segmentów mogą się zmieniać i zmieniać w czasie trwania połączenia. Na szczęście TCP nie musi rejestrować rozmiaru segmentu, z którym wcześniej wysyłane były poszczególne pakiety. Dlatego wykona następujące czynności:

  1. Za każdym razem, gdy nadejdzie ACK, przesuń wskaźnik odpowiednio do pierwszego niepotwierdzonego bajtu i odrzuć niepotrzebny bufor.
  2. Gdy zajdzie potrzeba retransmisji (Fast Retransmit lub Timeout; NIE natychmiast po otrzymaniu pierwszego ACK!), Ponownie wyśle ​​w aktualnie ważnym rozmiarze segmentu, zaczynając od wskaźnika do pierwszego niepotwierdzonego bajtu.

Obie operacje są wykonywane niezależnie od wielkości segmentu, do którego pierwotnie wysłano bajty. Teoria powinna pasować do większości implementacji.

Pozwól, że wyjaśnię:

Czy TCP używa bajtów lub segmentów? Do aplikacji TCP udostępnia interfejs strumienia bajtów. Ponadto wszystkie pola nagłówka i zmienne wewnętrzne są w bajtach. Jednak w celu przesłania informacji TCP dzieli je na segmenty, ponieważ wysyłanie bajtów jeden po drugim byłoby marnotrawstwem :-). Używanie liczników bajtów wszędzie ma tę zaletę, że rozmiar segmentu nie musi być stały przez cały czas trwania połączenia:

  • Wprowadzane są opcje, np. Piggybacking SACKa podczas retransmisji (prawdziwe implementacje napotykają to rzadko, jeśli w ogóle)
  • Zmiana MTU ścieżki, np. Jedno łącze wzdłuż ścieżki zmienia się na niższą MTU lub wąskie gardło łącza MTU jest podniesione. Dzieje się tak, gdy tworzone są tunele (VPN, PPPoE) lub protokół routingu wybiera inne łącze MTU. Dzieje się tak w IPv4 z ustawieniem Don't Fragment (prawdziwe dla większości współczesnych TCP); zawsze w TCPv6).

BTW: SACK nie jest tutaj odpowiedzią, ponieważ odbiornik (zwykle) użyje SACK tylko wtedy, gdy rozpozna dziurę w strumieniu bajtów (tj. Jeśli pakiet zostanie utracony, ale nadejdzie następny pakiet).

Marcel Waldvogel
źródło