Pourquoi avons-nous besoin d'une poignée de main à trois? Pourquoi ne pas simplement 2 voies?

124

La poignée de main TCP 3-way fonctionne comme ceci:

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

Pourquoi pas juste ça?

Client ------SYN-----> Server
Client <-----ACK------ Server
smwikipedia
la source
24
Pourquoi avons-nous même besoin d'une poignée de main? Pourquoi le message ne peut-il pas être envoyé avec le premier paquet?
Mehrdad
4
Si vous voulez passer la poignée de main, vous pouvez utiliser UDP à la place.
OzNetNerd
5
@Mehrdad, si vous avez une question à vous, utilisez le lien Poser une question en haut de la page pour poster la vôtre.
YLearn
40
@YLearn: Désolé, ce n'est pas vraiment une question qui m'est propre, mais c'était plutôt pour motiver les lecteurs à donner des réponses plus profondes que ce qui est littéralement énoncé dans la question.
Mehrdad
3
N'oubliez pas le TCP Fast Open (RFC 7413)
Alnitak

Réponses:

160

Décomposer la poignée de main dans ce qu'il fait vraiment.

Dans TCP, les deux parties gardent une trace de ce qu’elles ont envoyé en utilisant un numéro de séquence. Effectivement, il finit par être un nombre d'octets en cours de tout ce qui a été envoyé. La partie destinataire peut utiliser le numéro de séquence du locuteur opposé pour accuser réception de ce qu'elle a reçu.

Mais le numéro de séquence ne commence pas à 0. Il commence par le numéro de séquence initial (ISN), qui est une valeur choisie au hasard. Et comme TCP est une communication bidirectionnelle, les deux parties peuvent "parler" et doivent donc générer de manière aléatoire un ISN en tant que numéro de séquence de départ. Ce qui à son tour signifie que les deux parties doivent informer l’autre partie de leur numéro ISN de départ.

Donc, vous vous retrouvez avec cette séquence d'événements pour le début d'une conversation TCP entre Alice et Bob:

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]

Avis, quatre événements se produisent:

  1. Alice choisit un ISN et le synchronise avec Bob.
  2. Bob ACKnowledges l'ISN.
  3. Bob choisit un ISN et le synchronise avec Alice.
  4. Alice ACKnowledges l'ISN.

En réalité cependant, les deux événements du milieu (n ° 2 et n ° 3) se produisent dans le même paquet. Ce qui fait qu'un paquet est SYNou ACKest simplement un indicateur binaire activé ou désactivé à l'intérieur de chaque en- tête TCP , rien n'empêche donc l'activation de ces deux indicateurs sur le même paquet. Ainsi, la poignée de main à trois voies finit par être:

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

Notez les deux instances de "SYN" et "ACK", une de chaque, dans les deux sens.


Donc, pour revenir à votre question, pourquoi ne pas simplement utiliser une poignée de main bidirectionnelle? La réponse courte est qu’une poignée de main dans les deux sens ne permettrait à une partie d’établir un ISN et à l’autre de le reconnaître. Ce qui signifie qu'une seule partie peut envoyer des données.

Mais TCP est un protocole de communication bidirectionnel, ce qui signifie que chaque extrémité devrait pouvoir envoyer des données de manière fiable. Les deux parties doivent établir un numéro ISN, et les deux parties doivent reconnaître le numéro ISN de l'autre.

Donc, en réalité, ce que vous avez est exactement votre description de la poignée de main bidirectionnelle, mais dans chaque direction . Par conséquent, quatre événements se produisent. Et encore une fois, les deux drapeaux du milieu apparaissent dans le même paquet. En tant que tel, trois paquets sont impliqués dans un processus d'initiation de connexion TCP complet.

Eddie
la source
6
Pourquoi avons-nous besoin d'ISN? Les humains n'en ont pas besoin, pourquoi les ordinateurs? Y a-t-il une preuve de cela, ou est-ce que nous les avons simplement parce qu'elles sont pratiques?
Mehrdad
19
@Mehrdad: Vous avez besoin de numéros de séquence pour que les retransmissions fonctionnent correctement (voire pas du tout). L'ISN ne peut pas simplement être nul en raison d' attaques par prédiction de séquence .
Kevin
4
@Mehrdad La salle de discussion ne doit pas nécessairement être "en temps réel", nous pouvons laisser des messages les uns aux autres. La raison pour laquelle j'ai pensé le diriger ailleurs est parce que vous posez maintenant une question différente. Le PO a demandé "pourquoi est-ce une poignée de main à 3 voies au lieu de 2", mais maintenant vous vous demandez "pourquoi avons-nous besoin de numéros de séquence", ce qui est différent. Plutôt que de faire dérailler ce fil, j'ai pensé que nous devrions discuter de l'autre question dans le chat. Alternativement , vous pouvez poster une nouvelle question, je suis sûr que cela apportera de bonnes réponses.
Eddie
4
Super réponse concise. Lire "ACK SYN" est fondamentalement faux, mais vous avez même expliqué cela ainsi +1.
Lilienthal
3
Selon la RFC 793, Transmission Control Protocol : " La raison principale de la négociation à trois voies est d'éviter que de vieilles initiations de connexion en double ne créent de la confusion. "
Ron Maupin
23

La poignée de main à trois voies est nécessaire parce que les deux parties doivent syn chronize leurs numéros de séquence de segments utilisés au cours de leur transmission. A cet effet , chacune d'entre elles envoie (tour à tour) un segment SYN avec un numéro de séquence pour une valeur aléatoire n , qui est ensuite ack nowledged par l'autre partie par l' intermédiaire d' un segment d'accusé de réception avec un numéro de séquence à n + 1 .

dr01
la source
Pourquoi la reconnaissance est-elle nécessaire?
Paŭlo Ebermann
4
@ PaŭloEbermann: Parce que sinon, le serveur n'a aucune idée si le client a déjà reçu le SYN et il est important que le client le reçoive.
Mooing Duck
2
@ PaŭloEbermann Et pour le prouver, l'étape ACK consiste à reconnaître avec [X + 1]. - cité de Eddiecommentaire de à sa réponse.
smwikipedia
14

Pour que la connexion fonctionne, chaque côté doit vérifier qu'il peut envoyer des paquets à l'autre côté. Le seul moyen de vous assurer que vous avez reçu un paquet de l'autre côté est de recevoir d'eux un paquet qui, par définition, n'aurait pas été envoyé sans le paquet que vous avez envoyé . Pour ce faire, TCP utilise essentiellement deux types de messages: SYN (pour demander la preuve que ce paquet a bien traversé) et ACK (qui n'est envoyé qu'après qu'un SYN a réussi, pour prouver que le SYN est bien passé). Il y a en fait un troisième type de message, mais nous y reviendrons dans un instant.

Avant que la connexion ne commence, aucune des deux parties ne sait vraiment quoi que ce soit de l'autre. Le client envoie un paquet SYN au serveur afin de demander la preuve que ses messages peuvent passer . Cela ne dit rien à personne, mais c'est la première étape de la poignée de main.

Si le SYN réussit, le serveur sait que le client peut lui envoyer des paquets car, eh bien, cela vient de se produire. Mais cela ne prouve pas que le serveur peut renvoyer des paquets: les clients peuvent envoyer des SYN pour de nombreuses raisons . Le serveur doit donc renvoyer deux messages au client: un ACK (pour prouver que le SYN a réussi) et un SYN (pour demander un ACK). TCP combine ces deux messages en un seul message -a SYN-ACK, si vous voulez, pour réduire le trafic réseau. C'est la deuxième étape de la poignée de main.

Comme un SYN-ACK est un ACK, le client sait maintenant avec certitude qu'il peut envoyer des paquets au serveur. Et puisqu'un SYN-ACK est un SYN, il sait également que le serveur veut une preuve que ce message est passé. Donc, il renvoie un ACK: juste un ACK ordinaire, car il n'a plus besoin de preuve que ses paquets peuvent passer. Il s’agit de la dernière étape de la négociation: le client sait maintenant que les paquets peuvent aller dans les deux sens, et que le serveur est sur le point de comprendre cela (car il sait que le ACK passera).

Une fois que cet ACK est passé, le serveur sait maintenant qu'il peut envoyer des paquets au client . Il sait également que le client le sait, ce qui lui permet de commencer immédiatement à envoyer des données. La poignée de main est terminée. Nous avons un bon canal.

Eh bien, à proprement parler, nous ne pouvons pas être sûrs d' avoir un bon canal . Le fait que cette séquence de paquets soit passée ne garantit pas strictement que d’autres le feront. Nous ne pouvons pas prouver cela sans envoyer un nombre infini de SYN et ACK, et rien d'autre ne serait jamais fait. Ce n'est donc pas vraiment une option pratique. Mais dans la pratique, trois étapes s'avèrent suffisantes pour la plupart des objectifs .

Le Spooniest
la source
C'est faux: "un ACK (qui n'est envoyé qu'en réponse aux SYN, et prouve ainsi que le SYN a réussi)." L’indicateur SYN est défini sur le premier paquet envoyé de chaque extrémité et tous les paquets autres que le tout premier paquet de la négociation à 3 voies ont l’indicateur ACK défini. Le premier paquet ne peut pas ACK car la seconde partie n'a pas encore SYNed, mais chaque paquet après le premier doit accepter ce qui a déjà été reçu de l'autre extrémité, que des données soient renvoyées ou non.
Monty Harder
Merci. Reformulation: les ACK sont envoyés une fois qu'un SYN est passé, plutôt que d'être envoyés en réponse à des SYN.
Le
C’est la meilleure réponse qui puisse expliquer logiquement pourquoi nous avons même besoin du troisième message. Merci, Spooniest.
Parth Patel
7

En fait, une poignée de main à trois voies n'est pas le seul moyen d'établir une connexion TCP. L'échange SYN simultané est également autorisé: http://www.tcpipguide.com/free/t_TCPConnectionEstablishmentProcessTheThreeWayHandsh-4.htm

Cela pourrait être vu comme une sorte de double poignée de main à double sens.

Lexelby
la source
1
Bon point, cependant, cela est très rare car les deux appareils devront utiliser le même port source / destination et devront envoyer un SYN avant que l’autre ne reçoive le SYN. Même lorsque cela se produit, quatre paquets sont envoyés, ce qui est supérieur aux trois paquets requis par la négociation à trois voies traditionnelle; finalement, seule la possibilité d'être légèrement plus rapide à mettre en place en termes de temps total au prix d'une efficacité globale moindre (nécessite 33% de paquets en plus à transmettre).
YLearn
4

La connexion TCP est bidirectionnelle. Cela signifie que c'est en fait une paire de connexions à sens unique. L'initiateur envoie SYN, le répondeur envoie ACK: une connexion simplex commence. "Ensuite", le répondeur envoie SYN, l'initiateur envoie ACK: une autre connexion simplex commence. Deux connexions simplex forment une session TCP duplex, d'accord? Donc logiquement, il y a quatre étapes. mais comme les drapeaux SYN et ACK sont des "champs" différents de l'en-tête TCP, ils peuvent être configurés simultanément. Les deuxième et troisième étapes (sur les quatre) sont combinées, de sorte qu'il existe techniquement trois échanges de paquets. Chaque connexion simplex (demi) utilise un échange bidirectionnel, comme vous l'avez proposé.

Sergio
la source
2

Si le serveur et le client veulent créer une connexion, ils doivent confirmer quatre choses:

  1. Le serveur doit confirmer qu'il peut recevoir le paquet du client
  2. Le client doit confirmer qu'il peut recevoir le paquet du serveur

  3. Le client doit confirmer une chose: le serveur peut recevoir un paquet du client

  4. Le serveur doit confirmer une chose: le client peut recevoir un paquet du serveur

Après Client ------SYN-----> Server, la règle 1 est confirmée.

Après Client <---ACK/SYN---- Server, les règles 2 et 3 sont confirmées.

Donc, il faut un troisième paquet pour confirmer la règle 4.

codeman-cs est mon identifiant github
la source
1

Ce n'est pas nécessaire du tout. Il est évident qu'un message court ne doit nécessiter qu'un seul paquet vers le serveur, qui comprend le message start +, et un paquet l'accusé de réception.

Les réponses précédentes décrivent simplement le système sans discuter du besoin de numéros de séquence aléatoires, etc. La question initiale portait sur la conception du protocole TCP lui-même - si vous utilisez le protocole TCP, vous avez évidemment besoin de trois messages, car il s'agit du protocole. Mais pourquoi TCP a-t-il été conçu de cette manière?

Je crois que l’idée de départ était qu’il n’y avait pas de distinction entre les clients et les serveurs. Tous deux connaissaient les ports de l'autre d'une manière bidirectionnelle et l'un ou l'autre pouvait démarrer la conversation. Et cela nécessitait Syns etc.

Mais ce n'est pas, bien sûr, comment il est utilisé aujourd'hui. Le serveur écoute sur un port bien connu et accepte et "accepte", le numéro de port du client est éphémère. Je ne pense même pas qu'il soit possible pour un serveur en attente d'acceptation d'envoyer une requête à un autre sur le même numéro de port client dans les systèmes d'exploitation normaux.

(Notez qu'il s'agit d'une connexion bidirectionnelle, ce qui n'est jamais fait aujourd'hui. C'est très différent d'envoyer des messages bidirectionnels via une connexion une fois établie.)

Pour contourner l'inefficacité TCP, nous utilisons des protocoles tels que HTTP 1.1, qui peuvent réutiliser la même connexion pour plusieurs requêtes et éviter ainsi la négociation TCP qui n'était pas nécessaire en premier lieu.

Mais Http 1.1 est relativement nouveau. Et SSL / TLS avait besoin d’un moyen de réutiliser une session depuis le début en raison du coût des algorithmes PKI. Donc, ce protocole inclut son propre mécanisme de réutilisation de session qui s’exécute sur HTTP 1.1 qui s’exécute sur TCP.

Tel est le chemin avec le logiciel. Fudges sur kludges qui, une fois combinés, produisent un résultat acceptable.

Tuntable
la source
Tout ce qui se situe au-dessus de la couche 4 de l'OSI (par exemple, HTTP, FTP, etc.) est explicitement hors sujet ici. Dans les couches 1 à 4, il n’existe pas de client / serveur. TCP est une connexion entre pairs. Oui, les protocoles de couche supérieure créent une relation client / serveur, mais cela est hors sujet ici.
Ron Maupin
1
Soit dit en passant, HTTP utilise TCP, la négociation TCP est toujours nécessaire. Lisez le PROTOCOLE DE CONTRÔLE DE TRANSMISSION RFC 793 pour comprendre pourquoi. Les protocoles comme HTTP requièrent que l'application fasse le multiplexage que TCP ferait normalement pour l'application.
Ron Maupin
@RonMaupin La question initiale était pourquoi? Et la solution consiste à prendre en charge un cas d'utilisation qui, dans la pratique, n'est jamais utilisé par les couches supérieures. Donc, semble assez pertinent.
Tuntable
@RonMaupin Oui, HTTP utilise TCP. Ce que j'ai clarifié, merci. Mais cela ne rend pas la prise de contact TCP nécessaire dans un sens profond.
Tuntable
1
Les applications et les protocoles de couche d'application sont explicitement hors sujet ici. @ Eddie a répondu à la question, et si vous lisez et comprenez le RFC TCP, vous comprendrez pourquoi la poignée de main est nécessaire. Je ne pense pas que cela ajoute quoi que ce soit pour que vous affirmiez, sans aucun soutien, que la poignée de main n'est pas nécessaire, alors que c'est clairement le cas.
Ron Maupin
1

Après avoir lu la réponse d'Eddie (acceptée comme correcte), il reste à savoir pourquoi le premier hôte ne peut pas affecter les deux numéros ISN avec des nombres aléatoires et le 2e accepte simplement de l'accepter. La vraie raison d'utiliser la poignée de main à 3 voies est d'éviter les demi-connexions . Scénario de demi-connexion en négociation bidirectionnelle:
1) Client --- SYN -> Serveur
2) Le client change d’avis et ne veut plus se connecter
3) Client <-X-ACK-- Le serveur // ACK a été perdu
Le serveur ne voit pas le SYN renvoyé, il pense donc que le client a reçu son ACK et que la connexion est établie. En conséquence, le serveur a une connexion qui ne sera jamais fermée

Sanzhar Yeleuov
la source
En fait, si un hôte (les clients et les serveurs sont un concept d'application sur lequel TCP ne sait rien) reçoit un accusé de réception ou tout trafic sur une connexion inexistante (étape 3 de votre scénario), il enverra un RST sans ignorer le segment reçu. .
Ron Maupin
@RonMaupin Supposons alors la situation où le paquet ACK a été perdu.
Sanzhar Yeleuov
Si le ACK est perdu, la connexion établie à l'étape 1 expire. La RFC 793 explique en détail tous les types de scénarios, y compris les diagrammes.
Ron Maupin
@RonMaupin Je veux dire si le scénario de mon message reste le même, seule chose qui a changé, cet ACK a été perdu.
Sanzhar Yeleuov
Tout est dans le RFC. Jusqu'à ce qu'une connexion soit ouverte, tout trafic reçu donnera lieu à un RST. La négociation à trois voies négocie les paramètres de connexion afin que le "serveur" ne puisse rien renvoyer au "client" mais qu'il soit SYN / ACK jusqu'à ce qu'il reçoive un ACK du "client". Si le "serveur" SYN / ACK de nouveau au "client" est perdu, le "serveur" réessayera. Le RFC explique tout cela.
Ron Maupin