Dlaczego potrzebujemy 3-kierunkowego uścisku dłoni? Dlaczego nie tylko dwukierunkowy?

124

Uzgadnianie 3-kierunkowe TCP działa w następujący sposób:

Client ------SYN-----> Server
Client <---ACK/SYN---- Server
Client ------ACK-----> Server

Dlaczego nie tylko to?

Client ------SYN-----> Server
Client <-----ACK------ Server
smwikipedia
źródło
24
Dlaczego potrzebujemy nawet uścisku dłoni? Dlaczego nie można wysłać wiadomości z pierwszym pakietem?
Mehrdad
4
Jeśli chcesz pominąć uścisk dłoni, możesz zamiast tego użyć UDP.
OzNetNerd
5
@ Mehrdad, jeśli masz własne pytanie, skorzystaj z linku Zadaj pytanie u góry strony, aby opublikować własne.
YLearn
40
@YLearn: Przepraszam, to nie jest moje własne pytanie, ale raczej zmotywowanie czytelników do udzielenia odpowiedzi, które kopią nieco głębiej niż to, co jest dosłownie określone w pytaniu.
Mehrdad,
3
Nie zapomnij o TCP Fast Open (RFC 7413)
Alnitak

Odpowiedzi:

158

Rozbij uścisk dłoni na to, co naprawdę robi.

W TCP obie strony śledzą wysyłane wiadomości, używając numeru sekwencji. W efekcie jest to liczba bajtów bieżących wszystkiego, co zostało wysłane. Strona odbierająca może użyć numeru sekwencyjnego przeciwnego mówcy, aby potwierdzić otrzymaną wiadomość.

Ale numer kolejny nie zaczyna się od 0. Zaczyna się od ISN (Initial Sequence Number), czyli losowo wybranej wartości. A ponieważ TCP jest dwukierunkową komunikacją, obie strony mogą „mówić”, a zatem obie muszą losowo wygenerować numer ISN jako początkowy numer sekwencji. Co z kolei oznacza, że ​​obie strony muszą powiadomić drugą stronę o początkowym numerze ISN.

Tak więc kończy się następująca sekwencja zdarzeń na początek rozmowy TCP między Alicją i Bobem:

Alice ---> Bob    SYNchronize with my Initial Sequence Number of X
Alice <--- Bob    I received your syn, I ACKnowledge that I am ready for [X+1]
Alice <--- Bob    SYNchronize with my Initial Sequence Number of Y
Alice ---> Bob    I received your syn, I ACKnowledge that I am ready for [Y+1]

Uwaga, występują cztery zdarzenia:

  1. Alice wybiera numer ISN i synchronizuje go z Bobem.
  2. Bob AC Przyznaje numer ISN.
  3. Bob wybiera numer ISN i synchronizuje go z Alice.
  4. Alice AC uznaje nazwę ISN.

W rzeczywistości dwa środkowe zdarzenia (# 2 i # 3) mają miejsce w tym samym pakiecie. To, co sprawia, że ​​pakiet jest SYNlub ACKjest po prostu flagą binarną włączaną lub wyłączaną wewnątrz każdego nagłówka TCP , więc nic nie stoi na przeszkodzie, aby obie te flagi były włączone w tym samym pakiecie. Tak więc potrójny uścisk dłoni jest następujący:

Bob <--- Alice         SYN
Bob ---> Alice     SYN ACK 
Bob <--- Alice     ACK     

Zwróć uwagę na dwa wystąpienia „SYN” i „ACK”, po jednym w obu, w obu kierunkach.


Wracając do pytania, dlaczego nie skorzystać z dwukierunkowego uścisku dłoni? Krótka odpowiedź jest taka, że ​​dwukierunkowy uścisk dłoni pozwoliłby tylko jednej stronie na ustanowienie numeru ISN, a drugiej stronie na jego potwierdzenie. Co oznacza, że ​​tylko jedna strona może wysyłać dane.

Ale TCP jest dwukierunkowym protokołem komunikacyjnym, co oznacza, że ​​każdy z nich powinien być w stanie niezawodnie wysyłać dane. Obie strony muszą ustanowić numer ISN, a obie strony muszą potwierdzić numer ISN drugiej strony.

W efekcie masz dokładnie opis dwukierunkowego uścisku dłoni, ale w każdym kierunku . Stąd cztery zdarzenia. I znowu środkowe dwie flagi występują w tym samym pakiecie. W związku z tym trzy pakiety są zaangażowane w pełny proces inicjowania połączenia TCP.

Eddie
źródło
6
Dlaczego w ogóle potrzebujemy numerów ISN? Ludzie tego nie potrzebują, dlaczego komputery? Czy jest na to dowód, czy mamy je tylko dlatego, że są wygodne?
Mehrdad
19
@ Mehrdad: Potrzebujesz numerów sekwencyjnych, aby retransmisje działały poprawnie (a właściwie wcale). Numer ISN nie może wynosić tylko zero z powodu ataków przewidywania sekwencji .
Kevin,
4
@ Mehrdad Pokój czatu niekoniecznie musi być „w czasie rzeczywistym”, możemy zostawić sobie wiadomości. Powodem, dla którego postanowiłem skierować to gdzie indziej, jest to, że zadajesz teraz inne pytanie. OP zapytał „dlaczego to jest 3-drożny uścisk dłoni zamiast 2”, ale teraz pytasz „dlaczego w ogóle potrzebujemy liczb sekwencji”, co jest inne. Zamiast wykoleić ten wątek, pomyślałem, że powinniśmy omówić inne pytanie na czacie. Alternatywnie możesz opublikować nowe pytanie, jestem pewien, że uzyska kilka dobrych odpowiedzi.
Eddie
4
Świetna, zwięzła odpowiedź. Czytanie „ACK SYN” wydaje się zasadniczo błędne, ale nawet to wyjaśniłeś, więc +1.
Lilienthal,
3
Zgodnie z RFC 793, Protokół kontroli transmisji : „ Głównym powodem trójstronnego uzgadniania jest zapobieganie powodowaniu zamieszania przez zduplikowane inicjacje połączenia
Ron Maupin
23

The three-way handshake jest konieczne, ponieważ obie strony muszą TRANSMISSION chronize ich numery sekwencyjne segmentów stosowanych podczas ich przesyłania. W tym celu, każdy z nich wysyła (kolejno) segmentu SYN z numerem sekwencję losowej wartości n , który następnie ACK nowledged przez drugą stronę za pomocą segmentu ACK z numerem sekwencji ustawiony n + 1 .

dr01
źródło
Dlaczego potrzebne jest potwierdzenie?
Paŭlo Ebermann
4
@ PaŭloEbermann: Ponieważ inaczej Serwer nie ma pojęcia, czy klient kiedykolwiek otrzymał SYN, i ważne jest, aby klient to otrzymał.
Kaczka Mooing
2
@ PaŭloEbermann Aby to udowodnić, krokiem ACK jest potwierdzenie za pomocą [X + 1]. - cytował z Eddiekomentarza do swojej odpowiedzi.
smwikipedia,
14

Aby połączenie działało, każda strona musi sprawdzić, czy może wysyłać pakiety na drugą stronę. Jedynym sposobem, aby upewnić się, że dostałeś pakiet na drugą stronę, jest uzyskanie od nich pakietu, który z definicji nie zostałby wysłany, gdyby pakiet, który wysłałeś, nie przeszedł . TCP zasadniczo używa do tego dwóch rodzajów komunikatów: SYN (aby zażądać dowodu, że ten pakiet przeszedł) i ACK (który jest wysyłany dopiero po przejściu SYN, aby udowodnić, że SYN przeszedł). Jest właściwie trzeci rodzaj wiadomości, ale do tego przejdziemy za chwilę.

Przed rozpoczęciem połączenia żadna ze stron tak naprawdę nic nie wie o drugiej stronie. Klient wysyła pakiet SYN do serwera, aby zażądać dowodu, że jego wiadomości mogą się przedostać . To nic nie mówi żadnej osobie, ale jest to pierwszy krok uścisku dłoni.

Jeśli SYN przejdzie, serwer wie, że klient może wysyłać do niego pakiety, ponieważ, no cóż, tak się właśnie stało. Ale to nie dowodzi, że serwer może odsyłać pakiety z powrotem: klienci mogą wysyłać SYN z wielu powodów . Tak więc serwer musi wysłać dwa komunikaty z powrotem do klienta: ACK (aby udowodnić, że SYN przeszedł) i SYN (aby poprosić o własne ACK). TCP łączy te dwa komunikaty w jeden komunikat SYN-ACK, jeśli chcesz - w celu zmniejszenia ruchu w sieci. To drugi krok uścisku dłoni.

Ponieważ SYN-ACK jest ACK, klient wie teraz na pewno, że może wysyłać pakiety do serwera. A ponieważ SYN-ACK jest SYN, wie również, że serwer chce udowodnić, że ten komunikat został przesłany. Odsyła więc ACK: tym razem zwykłe ACK, ponieważ nie potrzebuje już dowodu, że jego pakiety mogą się przedostać. To jest ostatni krok uzgadniania: klient wie teraz, że pakiety mogą iść w obie strony, i że serwer zaraz się zorientuje (ponieważ wie, że ACK przejdzie).

Po przejściu tego ACK serwer wie, że może wysyłać pakiety do klienta . Wie również, że klient wie o tym, więc może natychmiast rozpocząć wysyłanie danych. Uścisk dłoni został zakończony. Mamy dobry kanał.

Ściśle mówiąc, nie możemy być pewni, że mamy dobry kanał . Tylko dlatego, że ta sekwencja pakietów dotarła nie bezwzględnie zagwarantować, że inni będą. Nie możemy tego udowodnić bez wysłania nieskończonej liczby SYN-ów i ACK-ów, a wtedy nic innego się nigdy nie da zrobić, więc to nie jest tak naprawdę praktyczna opcja. Ale w praktyce trzy kroki okazują się wystarczające do większości celów .

The Spooniest
źródło
To nieprawda: „ACK (które jest wysyłane tylko w odpowiedzi na SYN, a tym samym dowodzi, że SYN przeszedł).” Tylko pierwszy pakiet wysłany z każdego końca ma ustawioną flagę SYN, a wszystkie pakiety inne niż pierwszy pakiet 3-kierunkowego uzgadniania mają ustawioną flagę ACK. Pierwszy pakiet nie może ACK, ponieważ druga strona jeszcze nie SYNed, ale każdy pakiet po pierwszym musi ACK to, co zostało już odebrane z drugiego końca, niezależnie od tego, czy dane zostaną odesłane, czy nie.
Monty Harder
Dzięki. Nagrywanie: potwierdzenia są wysyłane po przejściu SYN, a nie tylko w odpowiedzi na SYN.
The Spooniest
To najlepsza odpowiedź, która może logicznie wyjaśnić, dlaczego potrzebujemy nawet trzeciej wiadomości. Dzięki, Spooniest.
Parth Patel
7

W rzeczywistości trójdrożny uścisk dłoni nie jest jedynym sposobem na nawiązanie połączenia TCP. Dozwolona jest również jednoczesna wymiana SYN: http://www.tcpipguide.com/free/t_TCPConnectionEstablishmentProcessTheThreeWayHandsh-4.htm

Można to uznać za rodzaj podwójnego dwukierunkowego uścisku dłoni.

Lexelby
źródło
1
Dobra uwaga, jednak jest to bardzo rzadkie, ponieważ oba urządzenia będą musiały używać tego samego portu źródłowego / docelowego, a oba urządzenia będą musiały wysłać SYN, zanim drugie odbierze SYN. Nawet gdy tak się dzieje, wiąże się to z wysłaniem czterech pakietów, co stanowi więcej niż trzy pakiety wymagane przez tradycyjny potrójny uścisk dłoni; ostatecznie jedynie możliwość nieco szybszej konfiguracji pod względem całkowitego czasu kosztem mniejszej ogólnej wydajności (wymaga przesłania o 33% większej liczby pakietów).
YLearn
4

Połączenie TCP jest dwukierunkowe. Oznacza to, że tak naprawdę jest to para połączeń jednokierunkowych. Inicjator wysyła SYN, odpowiadający wysyła ACK: rozpoczyna się jedno połączenie simpleks. „Następnie” respondent wysyła SYN, inicjator wysyła ACK: rozpoczyna się kolejne połączenie simpleks. Dwa połączenia simpleksowe tworzą jedną sesję dupleksową TCP, zgadzasz się? Logicznie więc w grę wchodzą cztery etapy; ale ponieważ flagi SYN i ACK są różnymi „polami” nagłówka TCP, można je ustawić jednocześnie - drugi i trzeci krok (z czterech) są połączone, więc technicznie istnieją trzy wymiany pakietów. Każde połączenie simpleks (pół) korzysta z dwukierunkowej wymiany, tak jak zaproponowałeś.

Sergio
źródło
2

Jeśli serwer i klient chcą utworzyć połączenie, muszą potwierdzić cztery rzeczy:

  1. Serwer musi potwierdzić, że może odebrać pakiet od klienta
  2. Klient musi potwierdzić, że może odebrać pakiet z serwera

  3. Klient musi coś potwierdzić: serwer może odbierać pakiet od klienta

  4. Serwer musi coś potwierdzić: Klient może odbierać pakiet z serwera

Po tym Client ------SYN-----> Serverreguła 1 zostaje potwierdzona.

Następnie Client <---ACK/SYN---- Serverreguły 2 i 3 zostają potwierdzone.

Tak więc potrzebny jest trzeci pakiet do potwierdzenia reguły 4.

codeman-cs to mój identyfikator github
źródło
1

To wcale nie jest konieczne. Oczywiste jest, że krótka wiadomość powinna wymagać tylko jednego pakietu do serwera, który zawiera komunikat start + i jeden pakiet potwierdzający to.

Poprzednie odpowiedzi po prostu opisują system bez omawiania potrzeby losowych numerów sekwencji itp. Pierwotne pytanie dotyczyło samej konstrukcji TCP - oczywiście jeśli używasz protokołu TCP, potrzebujesz trzech wiadomości, ponieważ taki jest protokół. Ale dlaczego TCP został tak zaprojektowany?

Uważam, że pierwotnym pomysłem było to, że nie było rozróżnienia między klientami a serwerami. Obaj znali porty drugiego w dwukierunkowy sposób i każdy mógł rozpocząć rozmowę. A to wymagało synchronizacji itp.

Ale nie jest to oczywiście sposób, w jaki jest dziś używany. Serwer nasłuchuje na dobrze znanym porcie i „akceptuje”, numer portu klienta jest efemeryczny. Nie sądzę nawet, aby serwer, który czeka na „zaakceptuj”, mógł wysłać żądanie do innego na tym samym numerze portu klienta w normalnych systemach operacyjnych.

(Należy pamiętać, że dotyczy to dwukierunkowego inicjowania połączenia, co nigdy nie jest wykonywane dzisiaj. Jest to zupełnie inne niż wysyłanie dwukierunkowych wiadomości w dół po ustanowieniu połączenia).

Aby obejść nieefektywność TCP, używamy protokołów takich jak HTTP 1.1, które mogą ponownie wykorzystywać to samo połączenie dla wielu żądań, a tym samym unikać uzgadniania TCP, który nie był konieczny.

Ale HTTP 1.1 jest stosunkowo nowy. A SSL / TLS potrzebował sposobu na ponowne wykorzystanie sesji od samego początku ze względu na koszt algorytmów PKI. Tak więc ten protokół zawiera własny mechanizm ponownego wykorzystania sesji, który działa na Http 1.1, który działa na TCP.

Tak jest z oprogramowaniem. Krówki na kostkach, które w połączeniu dają zadowalający wynik.

Tuntable
źródło
Wszystko powyżej warstwy 4 OSI (np. HTTP, FTP itp.) Jest tutaj wyraźnie nie na temat. W warstwach od 1 do 4 nie ma czegoś takiego jak klient / serwer. TCP to połączenie między peerami. Tak, protokoły wyższej warstwy tworzą relację klient / serwer, ale tutaj jest to nie na temat.
Ron Maupin
1
Nawiasem mówiąc, HTTP używa TCP, więc uzgadnianie TCP jest nadal konieczne. Przeczytaj RFC 793 PROTOKÓŁ KONTROLI TRANSMISJI, aby zrozumieć, dlaczego. Protokoły takie jak HTTP wymagają, aby aplikacja wykonała multipleksowanie, które normalnie TCP wykonałby dla aplikacji.
Ron Maupin
@RonMaupin Pierwotne pytanie brzmiało dlaczego? Odpowiedź brzmi: poprzeć przypadek użycia, który nigdy nie jest używany przez warstwy wyższego poziomu w praktyce. Wydaje się więc dość istotny.
Tuntable
@RonMaupin Tak, HTTP używa TCP. Które wyjaśniłem, dzięki. Ale to nie powoduje konieczności uzgadniania protokołu TCP w żadnym głębokim znaczeniu.
Tuntable
1
Aplikacje i protokoły warstwy aplikacji są tutaj wyraźnie nie na temat. @Eddie odpowiedział na pytanie, a jeśli czytasz i rozumiesz TCP RFC, zrozumiesz, dlaczego uzgadnianie jest konieczne. Nie sądzę, aby dodawało się do ciebie twierdzenie, bez żadnego wsparcia, że ​​uścisk dłoni nie jest konieczny, jeśli jest to oczywiste.
Ron Maupin
1

Po przeczytaniu odpowiedzi Eddiego (zaakceptowanej jako poprawna), wciąż pozostaje pytanie, dlaczego 1. host nie może przypisać obu numerów ISN losowymi liczbami, a drugi po prostu je akceptuje. Prawdziwym powodem korzystania z 3-kierunkowego uzgadniania jest unikanie pół połączeń . Scenariusz połowy połączenia w przypadku dwukierunkowego uzgadniania:
1) Klient --- SYN -> Serwer
2) Klient zmienia zdanie i nie chce się już podłączać
3) Klient <-X-ACK-- Serwer // ACK został utracony
Serwer nie widzi ponownie SYN, więc uważa, że ​​klient otrzymał potwierdzenie ACK i nawiązano połączenie. W rezultacie serwer ma połączenie, które nigdy nie zostanie zamknięte

Sanzhar Yeleuov
źródło
W rzeczywistości, jeśli host (klienci i serwery to koncepcja aplikacji, o której TCP nic nie wie) otrzymuje ACK lub dowolny ruch na nieistniejącym połączeniu (krok 3 w twoim scenariuszu), wyśle ​​RST, nie ignorując odebranego segmentu .
Ron Maupin
@RonMaupin Załóżmy zatem, że pakiet ACK został utracony.
Sanzhar Yeleuov
Jeśli potwierdzenie zostanie utracone, połączenie zainicjowane w kroku 1 przekroczy limit czasu. RFC 793 ma pełne wyjaśnienie wszystkich rodzajów scenariuszy, w tym diagramów.
Ron Maupin
@RonMaupin Mam na myśli to, że jeśli scenariusz z mojego postu pozostanie taki sam, zmieniła się tylko jedna rzecz: utracono ACK.
Sanzhar Yeleuov
Wszystko jest w RFC. Dopóki połączenie nie zostanie otwarte, każdy odebrany ruch będzie skutkował RST. Trójstronny uścisk dłoni negocjuje parametry połączenia, więc „serwer” nie może wysłać niczego z powrotem do „klienta”, ale jest to SYN / ACK, dopóki nie otrzyma potwierdzenia od „klienta”. Jeśli „serwer” SYN / ACK z powrotem do „klienta” zostanie utracony, „serwer” spróbuje ponownie. RFC wyjaśnia to wszystko.
Ron Maupin