Por que precisamos de um aperto de mão de três vias? Por que não apenas bidirecional?


124

O handshake de 3 vias do TCP funciona assim:

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

Por que não apenas isso?

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

24
Por que precisamos de um aperto de mão? Por que a mensagem não pode ser enviada com o primeiro pacote?
Mehrdad

4
Se você quiser pular o aperto de mão, poderá usar o UDP.
OzNetNerd #

5
@Mehrdad, se você tiver alguma dúvida, use o link Perguntar na parte superior da página para postar a sua.
YLearn

40
@YLearn: Desculpe, não é realmente uma pergunta minha, mas sim para motivar os leitores a dar respostas que se aprofundam um pouco mais do que o que está literalmente indicado na pergunta.
Mehrdad

3
Não se esqueça do TCP Fast Open (RFC 7413)
Alnitak

Respostas:


160

Divida o aperto de mão no que realmente está fazendo.

No TCP, as duas partes controlam o que foram enviadas usando um número de sequência. Efetivamente, acaba sendo uma contagem de bytes em execução de tudo o que foi enviado. A parte receptora pode usar o número de sequência do falante oposto para confirmar o que recebeu.

Mas o número de sequência não começa em 0. Ele começa no ISN (Número de sequência inicial), que é um valor escolhido aleatoriamente. E como o TCP é uma comunicação bidirecional, ambas as partes podem "falar" e, portanto, ambas devem gerar aleatoriamente um ISN como número de sequência inicial. O que, por sua vez, significa que ambas as partes precisam notificar a outra parte de seu ISN inicial.

Então, você acaba com essa sequência de eventos para iniciar uma conversa TCP entre Alice e 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]

Observe que quatro eventos estão ocorrendo:

  1. Alice escolhe um ISN e o sincroniza com Bob.
  2. Bob reconhece o ISN.
  3. Bob escolhe um ISN e o sincroniza com Alice.
  4. Alice reconhece o ISN.

Na realidade, porém, os dois eventos do meio (# 2 e # 3) acontecem no mesmo pacote. O que faz um pacote ser SYNou ACKsimplesmente um sinalizador binário ativado ou desativado dentro de cada cabeçalho TCP , portanto, não há nada impedindo que esses dois sinalizadores sejam ativados no mesmo pacote. Portanto, o aperto de mão triplo acaba sendo:

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

Observe as duas instâncias de "SYN" e "ACK", uma de cada, nas duas direções.


Então, voltando à sua pergunta, por que não usar apenas um aperto de mão bidirecional? A resposta curta é porque um aperto de mão bidirecional permitiria apenas que uma parte estabelecesse um ISN e a outra parte o reconhecesse. O que significa que apenas uma parte pode enviar dados.

Mas o TCP é um protocolo de comunicação bidirecional, o que significa que qualquer extremidade deve poder enviar dados de maneira confiável. Ambas as partes precisam estabelecer um ISN, e ambas precisam reconhecer o ISN da outra.

Na verdade, o que você tem é exatamente a sua descrição do handshake de mão dupla, mas em cada direção . Portanto, quatro eventos ocorrendo. E, novamente, as duas bandeiras do meio acontecem no mesmo pacote. Como tal, três pacotes estão envolvidos em um processo completo de inicialização da conexão TCP.


6
Por que precisamos de ISNs? Os humanos não precisam disso, por que os computadores? Existe uma prova disso, ou apenas as temos porque são convenientes?
Mehrdad

19
@ Mehrdad: Você precisa de números de sequência para que as retransmissões funcionem corretamente (ou mesmo). O ISN não pode ser zero por causa de ataques de previsão de sequência .
Kevin

4
@Mehrdad A sala de bate-papo não precisa necessariamente ser 'tempo real'; podemos deixar mensagens um para o outro. A razão pela qual pensei em direcioná-lo para outro lugar é porque agora você está fazendo uma pergunta diferente. O OP perguntou "por que é um aperto de mão de três vias em vez de 2", mas agora você está questionando "por que precisamos de números de sequência?", O que é diferente. Em vez de desviar essa discussão, pensei que deveríamos discutir a outra questão no chat. Como alternativa , você pode postar uma nova pergunta, tenho certeza de que ela fornecerá boas respostas.
Eddie

4
Ótima resposta concisa. Ler "ACK SYN" parece fundamentalmente errado, mas você até explicou isso com +1.
Lilienthal

3
De acordo com a RFC 793, Transmission Control Protocol : " A principal razão para o handshake de três vias é impedir que antigas iniciações de conexão duplicada causem confusão. "
Ron Maupin

23

O handshake de três vias é necessário porque ambas as partes precisam syn chronize seus números de sequência de segmentos utilizados durante a sua transmissão. Para isso, cada um deles envia (por sua vez) um segmento SYN com um número de sequência definida para um valor aleatório n , o qual é então ack nowledged pela outra parte, através de um segmento ACK com um número de sequência definida como n + 1 .


Por que o reconhecimento é necessário?
Paŭlo Ebermann 4/11/15

4
@ PaŭloEbermann: Porque, caso contrário, o servidor não tem idéia se o cliente já recebeu o SYN, e é importante que o cliente o receba.
Mooing Duck

2
@ PaŭloEbermann E para provar isso, o passo ACK é confirmar com [X + 1]. - citou Eddieo comentário de sua resposta.
smwikipedia

14

Para que a conexão funcione, cada lado precisa verificar se pode enviar pacotes para o outro lado. A única maneira de garantir que você tenha um pacote para o outro lado é obtendo um pacote deles que, por definição, não teria sido enviado a menos que o pacote que você enviou passasse . O TCP basicamente usa dois tipos de mensagens para isso: SYN (para solicitar prova de que esse pacote foi aprovado) e ACK (que é enviado apenas após a conclusão de um SYN, para provar que o SYN foi aprovado). Na verdade, existe um terceiro tipo de mensagem, mas chegaremos a isso em um momento.

Antes de a conexão iniciar, nenhum dos lados realmente sabe algo sobre o outro. O cliente envia um pacote SYN para o servidor, para solicitar prova de que suas mensagens podem passar . Isso não diz nada a ninguém, mas é o primeiro passo do aperto de mão.

Se o SYN passar, o servidor saberá que o cliente pode enviar pacotes para ele, porque, bem, aconteceu. Mas isso não prova que o servidor possa enviar pacotes de volta: os clientes podem enviar SYNs por vários motivos . Portanto, o servidor precisa enviar duas mensagens de volta ao cliente: um ACK (para provar que o SYN foi aprovado) e um SYN (para solicitar um ACK próprio). O TCP combina essas duas mensagens em uma - uma mensagem SYN-ACK, se você desejar - para reduzir o tráfego de rede. Este é o segundo passo do aperto de mão.

Como um SYN-ACK é um ACK, o cliente agora tem certeza de que pode enviar pacotes para o servidor. E como um SYN-ACK é um SYN, ele também sabe que o servidor deseja uma prova de que essa mensagem foi recebida. Portanto, ele envia de volta um ACK: apenas um ACK simples desta vez, porque não precisa mais de provas de que seus pacotes podem passar. Esta é a etapa final do handshake: o cliente agora sabe que os pacotes podem ir nos dois sentidos e que o servidor está prestes a descobrir isso (porque sabe que o ACK será executado).

Depois que o ACK é concluído, agora o servidor sabe que pode enviar pacotes para o cliente . Ele também sabe que o cliente sabe disso, para que possa começar a enviar dados imediatamente. O aperto de mão está completo. Temos um bom canal.

Bem, a rigor, não podemos ter certeza de que temos um bom canal . Só porque essa sequência de pacotes passou não garante estritamente que outros o farão. Não podemos provar isso sem enviar um número infinito de SYNs e ACKs, e então nada mais seria feito; portanto, essa não é realmente uma opção prática. Mas, na prática, três etapas são boas o suficiente para a maioria dos propósitos .


Isso é falso: "um ACK (que apenas é enviado em resposta a SYNs e, portanto, prova que o SYN foi aprovado)". Somente o primeiro pacote enviado de cada extremidade tem o sinalizador SYN definido e todos os pacotes, exceto o primeiro pacote do handshake de três vias, têm o sinalizador ACK definido. O primeiro pacote não pode ACK porque a segunda parte ainda não foi sincronizada, mas todos os pacotes após o primeiro devem aceitar o que já foi recebido da outra extremidade, independentemente de quaisquer dados serem enviados de volta ou não.
Monty Mais difícil

Obrigado. Reescrita: os ACKs são enviados assim que um SYN é transmitido, em vez de apenas serem enviados em resposta aos SYNs.
O Spooniest

Esta é a melhor resposta que pode explicar logicamente por que precisamos da terceira mensagem. Obrigado, Spooniest.
Parth Patel

7

Na verdade, um handshake de três vias não é o único meio de estabelecer uma conexão TCP. A troca simultânea de SYN também é permitida: http://www.tcpipguide.com/free/t_TCPConnectionEstablishmentProcessTheThreeWayHandsh-4.htm

Isso pode ser visto como um tipo de aperto de mão duplo.


1
Bom ponto, no entanto, isso é muito raro, pois os dois dispositivos precisarão usar a mesma porta de origem / destino e os dois dispositivos precisarão enviar um SYN antes que o outro receba o SYN. Mesmo quando ocorre, envolve o envio de quatro pacotes, o que é mais do que os três pacotes exigidos pelo handshake de três vias tradicional; em última análise, apenas a possibilidade de ser um pouco mais rápida de configurar em termos de tempo geral, com o custo de menos eficiência geral (requer 33% a mais de pacotes a serem transmitidos).
YLearn

4

A conexão TCP é bidirecional. O que isso significa é que, na verdade, é um par de conexões unidirecionais. O iniciador envia SYN, o respondente envia ACK: uma conexão simplex é iniciada. "Então" o respondente envia SYN, o iniciador envia ACK: outra conexão simplex é iniciada. Duas conexões simplex formam uma sessão TCP duplex, concorda? Então, logicamente, existem quatro etapas envolvidas; mas como os sinalizadores SYN e ACK são "campos" diferentes do cabeçalho TCP, eles podem ser definidos simultaneamente - a segunda e a terceira etapas (das quatro) são combinadas, portanto tecnicamente há três trocas de pacotes. Cada conexão simplex (meia) usa troca bidirecional, como você propôs.


2

Se o Servidor e o Cliente desejam criar uma conexão, eles precisam confirmar quatro coisas:

  1. O servidor precisa confirmar que ele pode receber pacotes do cliente
  2. O cliente precisa confirmar que pode receber pacotes do servidor

  3. O cliente precisa confirmar uma coisa: o servidor pode receber pacotes do cliente

  4. O servidor precisa confirmar uma coisa: o cliente pode receber pacotes do servidor

Depois Client ------SYN-----> Server, a regra 1 é confirmada.

Depois Client <---ACK/SYN---- Server, as regras 2 e 3 são confirmadas.

Portanto, é necessário um terceiro pacote para confirmar a regra 4.


1

Não é necessário. É óbvio que uma mensagem curta deve exigir apenas um pacote para o servidor, que inclui a mensagem start +, e um pacote novamente reconhecendo-o.

As respostas anteriores apenas descrevem o sistema sem discutir a necessidade de números de sequência aleatórios etc., em primeiro lugar. A pergunta original era sobre o design do próprio TCP - obviamente, se você usar o protocolo TCP, precisará de três mensagens, porque esse é o protocolo. Mas por que o TCP foi projetado dessa maneira em primeiro lugar?

Acredito que a ideia original era que não havia distinção entre clientes e servidores. Ambos conheciam os portos do outro de maneira bidirecional e podiam iniciar a conversa. E isso exigia Syns etc.

Mas não é, claro, como é usado hoje. O servidor escuta em uma porta conhecida e faz e "aceita", o número da porta do cliente é efêmero. Eu nem acho que é possível para um servidor aguardando um "aceitar" enviar uma solicitação para outro no mesmo número de porta do cliente em sistemas operacionais normais.

(Observe que se trata de iniciação bidirecional da conexão, o que nunca é feito hoje. Isso é bem diferente de enviar mensagens bidirecionais para uma conexão estabelecida uma vez.)

Para contornar a ineficiência do TCP, usamos protocolos como o HTTP 1.1, que podem reutilizar a mesma conexão para várias solicitações e, assim, evitar o handshake do TCP que não era necessário em primeiro lugar.

Mas o HTTP 1.1 é relativamente novo. E o SSL / TLS precisava de uma maneira de reutilizar a sessão desde o início devido ao custo dos algoritmos da PKI. Portanto, esse protocolo inclui seu próprio mecanismo de reutilização de sessão, executado em cima do HTTP 1.1, que é executado em cima do TCP.

É assim com o software. Fudges em kludges que, quando combinados, produzem um resultado aceitável.


Qualquer coisa acima da camada 4 do OSI (por exemplo, HTTP, FTP etc.) está explicitamente fora de tópico aqui. Nas camadas 1 a 4, não existe cliente / servidor. TCP é uma conexão entre pares. Sim, os protocolos da camada superior criam um relacionamento cliente / servidor, mas isso não é tópico aqui.
Ron Maupin

1
A propósito, o HTTP usa TCP, portanto o handshake TCP ainda é necessário. Leia o RFC 793 PROTOCOLO DE CONTROLE DE TRANSMISSÃO para entender o porquê. Protocolos como HTTP exigem que o aplicativo faça a multiplexação que o TCP normalmente faria para o aplicativo.
Ron Maupin

@RonMaupin A pergunta original era por quê? E a resposta é suportar um caso de uso que nunca é usado pelas camadas de nível superior na prática. Então, parece bastante relevante.
Tuntable

@RonMaupin Sim, o HTTP usa TCP. O que eu esclareci, obrigado. Mas isso não torna necessário o aperto de mão TCP em nenhum sentido profundo.
Tuntable

1
Os aplicativos e protocolos da camada de aplicativo estão explicitamente fora de tópico aqui. @ Eddie respondeu à pergunta e, se você ler e entender o TCP RFC, entenderá por que o aperto de mão é necessário. Acho que não acrescenta nada para você reivindicar, sem nenhum apoio, que o aperto de mão não é necessário, quando é claramente.
Ron Maupin

1

Depois de ler a resposta de Eddie (aceito como correto), ainda há dúvidas sobre o motivo pelo qual o primeiro host não pode atribuir ambos os ISNs com números aleatórios e o segundo apenas aceita. O verdadeiro motivo do uso do handshake de três vias é evitar meias conexões . Cenário de meia conexão no handshake bidirecional:
1) Cliente --- SYN -> Servidor
2) O cliente muda de idéia e não deseja mais se conectar
3) Cliente <-X-ACK-- Servidor // ACK foi perdido
O servidor não vê SYN reenviado, então ele acha que o cliente recebeu seu ACK e a conexão foi estabelecida. Como resultado, o servidor possui uma conexão que nunca será fechada


Na verdade, se um host (clientes e servidores é um conceito de aplicativo sobre o qual o TCP não sabe nada) recebe um ACK ou qualquer tráfego em uma conexão inexistente (etapa 3 no seu cenário), ele envia um RST, não ignora o segmento recebido .
Ron Maupin

@ RonMaupin Então vamos assumir a situação em que o pacote ACK foi perdido.
Sanzhar Yeleuov

Se o ACK for perdido, a conexão iniciada na etapa 1 expirará. O RFC 793 tem uma explicação completa de todos os tipos de cenários, incluindo diagramas.
Ron Maupin

@RonMaupin Quero dizer, se o cenário do meu post permanecer o mesmo, a única coisa que mudou, que o ACK foi perdido.
Sanzhar Yeleuov

Está tudo na RFC. Até uma conexão ser aberta, qualquer tráfego recebido resultará em um RST. O handshake de três vias negocia os parâmetros de conexão, de modo que o "servidor" não pode enviar nada de volta ao "cliente", mas é SYN / ACK até receber um ACK do "cliente". Se o "servidor" SYN / ACK voltar ao "cliente" for perdido, o "servidor" tentará novamente. A RFC explica tudo isso.
Ron Maupin
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.