Algoritmo de Nagle, ACK Delay e Rlogin echo

3

Estou lendo sobre o fluxo de dados TCP, ACK atrasado e Algoritmo de Nagle .

Até agora eu entendo que:

  1. A implementação ACK atrasada no TCP cria um atraso no reconhecimento de segmentos recebidos para dar a oportunidade para o aplicativo gravar alguns dados junto com a confirmação, evitando assim enviar um pacote ACK vazio e contribuindo para o congestionamento da rede.
  2. A implementação do Algoritmo de Nagle indica que você não pode enviar um pequeno segmento TCP enquanto outro segmento pequeno ainda não é reconhecido. Isso evita que o tráfego seja carregado com vários tinygrams .

Em alguns aplicativos interativos, como o Rlogin, por exemplo, o Algoritmo de Nagle e ACKs atrasados podem "conflitar":

O Rlogin envia a entrada do teclado para o servidor enquanto os digitamos e algumas teclas (como F1 ) geram mais de um byte ( F1 = Escape + colchete esquerdo + M ). Esses bytes podem ser enviados em segmentos diferentes se forem entregues ao TCP um por um.

O servidor não responde com um eco até que tenha toda a sequência, portanto, todos os ACKs seriam atrasados (esperando alguns dados do aplicativo). O cliente, por outro lado, aguardaria o primeiro reconhecimento de byte antes de enviar o próximo (respeitando o Algoritmo de Nagle ). Essa combinação acaba resultando em um Rlogin "lento".

A tcpdump da chave F1 e F2 enviada em um Rlogin é representada abaixo:

    type Fl key
1   0.0                 slip.1023 > vangogh. login: P 1:2(1) ack 2
2   0.250520 (0.2505)   vangogh.login > slip.1023: P 2:4(2) ack 2
3   0.251709 (0.0012)   slip.1023 > vangogh.login: P 2:4(2) ack 4
4   0.490344 (0.2386)   vangogh.login > slip.1023: P 4:6(2) ack 4
5   0.588694 (0.0984)   slip.1023 > vangogh.login: . ack 6
    type F2 key
6   2.836830 (2.2481)   slip.1023 > vangogh.login: P 4:5(1) ack 6
7   3.132388 (0.2956)   vangogh.login > slip.1023: P 6:8(2) ack 5
8   3.133573 (0.0012)   slip.1023 > vangogh.login: P 5:7(2) ack 8
9   3.370346 (0.2368)   vangogh.login > slip.1023: P 8:10(2) ack 7
10  3.388692 (0.0183)   slip.1023 > vangogh.login: . ack 10

Agora a dúvida: Embora a página que leio afirme que o servidor não responde com um eco antes de ter toda a sequência de teclas, os pacotes capturados por tcpdump mostram que as chaves estão sendo ecoadas em seus respectivos ACKs (a primeira resposta tem 2 bytes de comprimento porque o eco de ESC é de dois caracteres - acento circunflexo + colchete esquerdo).

Se os dados estão sendo enviados do aplicativo para TCP (a resposta de eco), por que os ACKs estão atrasados? De acordo com o que foi dito, o servidor esperando a sequência completa antes de ecoar , os ACKs não deveriam conter nenhum eco até o último ACK, que conteria toda a sequência echo?

Referência: link

    
por IanC 14.08.2016 / 22:58

2 respostas

1

Você diz que o rlogin "server não responde com um eco até que ele tenha toda a sequência", como o usual ^[OP para a tecla F1. Mas isso é apenas uma suposição injustificada. E um errado. E sua experiência com o tcpdump mostra que esse não é o caso; mostra exatamente uma implementação de rlogin atrasada sem qualquer "otimização".

De fato, um comportamento normal e esperado para o servidor é ecoar imediatamente qualquer entrada. Se o cliente, por algum motivo, decidir enviar ^[ sozinho, ele não experimentará um atraso estranho depois disso ((deixando de lado o TCP completamente).

O que deve ser uma solução limpa para a classe de problemas lag-rlogin, é que cada lado da conversação (ambos cliente e servidor) somente send() quando eles Acredito sinceramente que neste momento algum humano está esperando que o resultado seja exibido. Sob tal restrição, é um grande erro no cliente enviar ^[ , quando o software já sabe que ^[OP é a sequência completa pretendida e um usuário humano está interessado no resultado completo, não apenas no resultado de ^[ (um humano decide enviar OP ou talvez OQ em resposta, ou o quê?).

Então, o contra-intuitivo conselho para desenvolvedores de software, qualquer que seja o seu negócio com o TCP e eles desenvolvem lado do cliente ou servidor: lembre-se que send() não é imediato, possivelmente atrasará sua próxima transferência, então use com mais cuidado (resultado do acréscimo de latência do Nagle com ACK atrasado adicionando ainda mais latência).

    
por 06.10.2016 / 08:59
1

AFAIK o Algoritmo do Nagle é definido em um nível muito baixo da configuração do soquete. Por exemplo, as implementações C / C ++ da comunicação de soquete estão usando API de nível muito baixo para desativá-lo.

A idéia do Nagle é muito boa no uso típico do TCP / IP.

Por exemplo, tínhamos usado algumas bibliotecas de mensagens para o sistema em tempo real e nós explicitamente o desligamos no nível do soquete. Exatamente por esse motivo. Nós não queremos esperar. Com o soquete do Nagle aguarda até que o buffer completo esteja cheio - independentemente do tipo da mensagem. Assim, os ACKs são atrasados, pois todos eles são pequenos e o buffer estará lentamente cheio.

Mas as dicas práticas são as seguintes: 1. Desligue o Algoritmo de Nagle ou 2. Se você não puder, envie mensagens maiores, então o buffer de Nagle fica cheio.

    
por 06.10.2016 / 06:59