se um pacote TCP for parcialmente reconhecido, como o mecanismo de retransmissão reagirá?

12

se um cliente tcp enviar um pacote, com número de sequência de 10000 a 20000, para um servidor tcp. o tcp responderá com um ACK com seq_ack 20001.

se eu interceptar o pacote TCP do cliente e dividir o pacote em 2 segmentos tcp, um com seq de 10000 a 15000 e outro com seq de 15001 a 20000. E esses dois segmentos TCP serão enviados ao servidor TCP. Suponha que o segundo segmento esteja perdido no caminho. O servidor TCP responderá um ACK com seq_ack 15001.

Agora, como o cliente TCP envia um pacote integral com seq 10000 a 20000, mas recebe um ACK com 15001, do ponto de vista do cliente, isso é estranho. Como isso vai reagir? Em teoria, o cliente deve retransmitir os bytes da seq 15001 a 20000, ou seja, o cliente transmitirá novos pacotes da seq 15001. Mas e quanto à prática, na implementação da pilha TCP, é a mesma da teoria?

Eu acho que no buffer de envio TCP, quando um segmento TCP é enviado, o segmento ainda permanece lá até o ACK. Quando o ACK chega, esses bytes para o segmento são limpos do buffer. Há um ponteiro no buffer de envio. Quando um ACK chega, o ponteiro aponta para o local em que o ack_seq corresponde. Os bytes que estão abaixo do ack_seq são limpos. Dessa forma, o segmento inteiro não precisa ser retransmitido?

misteryes
fonte

Respostas:

8

Isso é chamado de reconhecimento seletivo e já está incluído na especificação TCP definida no RFC 2018 . Isso permitiria ao cliente reenviar apenas os bytes 15001 a 20000 (já que eles estão em pacotes / segmentos diferentes, se você os tiver dividido como você diz), mas o mais interessante é que até permite reconhecimentos fora de ordem.

Do RFC 2018:

Ao receber um ACK contendo uma opção SACK, o remetente de dados DEVE gravar o reconhecimento seletivo para referência futura. O remetente de dados é considerado como tendo uma fila de retransmissão que contém os segmentos que foram transmitidos, mas ainda não reconhecidos, na ordem do número de sequência.

O suporte nãoSACK é requerido pela especificação TCP. Se o cliente ou o servidor não suportassem reconhecimento seletivo, na verdade todos os bytes 10000 a 20000 teriam que ser retransmitidos.

Na implementação da pilha TCP, é o mesmo que na teoria?

Geralmente SACK é suportado, pois os ganhos de desempenho, eficiência e latência são significativos - especialmente em uma rede como a Internet.

De fato, no entanto, essas suposições devem ser verdadeiras, mesmo se você manipular manualmente os pacotes, como afirmou. De acordo com RFC 793 , no mínimo, a janela de dados inteiro terá de ser retransmitido, mas o receptor não sabe que os dados recebidas é de pelo menos válida . Para detalhes da implementação, Seção 3.3 - Números de sequência do RFC 793.

Para obter uma descrição geral de todo o processo, com e sem suporte de reconhecimento seletivo, consulte este artigo (que inclui alguns diagramas muito úteis).

Avanço
fonte
é um pouco estranho para mim, porque o TCP é baseado em protocolo orientado a bytes. Por que deveria retransmitir todo o segmento? Parece-me que o TCP sem SAKC é um protocolo de fluxo orientado a segmentos, mas o TCP com Sack é orientado a bytes reais. Eu acho que a RFC não elabora especificamente sobre isso.
misteryes
como a pilha TCP gerencia seu buffer de envio, é igual ao que escrevi na pergunta atualizada.
misteryes
@misteryes este artigo descreve o processo (com alguns ótimos diagramas também!).
Revelação
No link que você recomendou, parece que o autor ainda discute o problema de maneira orientada por segmento, não de maneira real, orientada a bytes. Não é?
misteryes
1
Eu conhecia o SACK antes de postar esta pergunta. No começo, não acho que o SACK tenha algo a ver com essa pergunta. Na minha opinião, se o TCP não é orientado a bytes, mas orientado a segmentos, o SACK também deve ser o mesmo. A diferença entre o SACK ativado e o SACK desativado é que, com o SACK, o TCP permite um furo de sequência no ack_seq. Mas eu pensei que o furo da sequência corresponde a um segmento. enquanto, de acordo com o seu ditado, o buraco pode ser metade / parte de um segmento.
Misteryes
3

Os tamanhos dos segmentos podem (e mudam) durante a vida útil de uma conexão. Felizmente, o TCP não precisa registrar o tamanho do segmento com o qual os pacotes individuais foram enviados anteriormente. Portanto, ele fará o seguinte:

  1. Sempre que um ACK chegar, avance o ponteiro para o primeiro byte não reconhecido de acordo e descarte qualquer buffer agora desnecessário.
  2. Quando surgir a necessidade de retransmissão (Retransmissão Rápida ou Tempo Limite; NÃO imediatamente após o recebimento do primeiro ACK!), Ele será reenviado no tamanho de segmento atualmente válido, começando do ponteiro para o primeiro byte não reconhecido.

Ambas as operações são realizadas independentemente do tamanho do segmento em que esses bytes foram originalmente enviados. Portanto, a teoria deve corresponder à maioria das implementações.

Deixe-me dar uma explicação para explicar:

O TCP usa bytes ou segmentos? Para o aplicativo, o TCP expõe uma interface de fluxo de bytes. Além disso, todos os campos do cabeçalho e variáveis ​​internas estão em bytes. No entanto, para transmitir informações, o TCP as divide em segmentos, pois o envio de bytes um por um seria um grande desperdício :-). O uso de contadores de bytes em qualquer lugar tem a vantagem de que o tamanho do segmento não precisa permanecer constante durante a vida útil da conexão:

  • Estão sendo introduzidas opções, por exemplo, pegando carona em um SACK em uma retransmissão (implementações reais raramente encontrarão isso, se houver)
  • A MTU do caminho muda, por exemplo, um link ao longo do caminho muda para uma MTU mais baixa ou o link da MTU com gargalo é aumentado. Isso acontece quando os túneis são estabelecidos (VPN, PPPoE) ou o protocolo de roteamento seleciona um link MTU diferente. Isso acontece no IPv4 com o Não fragmentar definido (verdadeiro para a maioria dos TCPs modernos); sempre no TCPv6).

BTW: SACK não é a resposta aqui, pois o receptor (normalmente) só usará o SACK se reconhecer um furo no fluxo de bytes (ou seja, se um pacote for perdido, mas um pacote seguinte chegar).

Marcel Waldvogel
fonte