Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

07 - Controle de Fluxo (Sliding Window)

video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

O Controle de Fluxo (Flow Control) é o mecanismo de regulação que impede que um remetente TCP sobrecarregue o buffer de recepção do destino. A técnica central utilizada é a Janela Deslizante (Sliding Window), em que o receptor anuncia continuamente quanto espaço livre tem disponível. Esse mecanismo é definido na RFC 793 e estendido na RFC 7323 (Window Scaling).

1. Motivação: Por que Controlar o Fluxo?

Mesmo que a rede seja rápida e o remetente tenha muita largura de banda, o computador receptor pode ter uma CPU lenta ou pouca memória RAM disponível para processar os dados recebidos. Se o remetente enviar dados mais rápido do que o receptor consegue ler (recv()/read()) da socket, o buffer de recepção do receptor encherá e começará a descartar novos pacotes — desperdiçando largura de banda com dados que serão retransmitidos.

O controle de fluxo resolve esse problema localmente, entre os dois hosts fim-a-fim, sem envolver a rede (ao contrário do controle de congestionamento, que é uma regulação contra a rede).

2. Conceito de Janela Deslizante

A "janela" é o intervalo de bytes que o remetente pode enviar sem ter recebido ACK. À medida que chegam ACKs, a janela desliza para a direita (frente), liberando novos bytes para envio.

Variáveis principais (definidas na RFC 793 e refinadas em implementações modernas):

Variável Significado
SND.UNA Número do primeiro byte não confirmado (left edge da janela)
SND.NXT Número do próximo byte a ser enviado
SND.WND Tamanho da janela de envio (anunciado pelo receptor)
SND.MAX Limite superior: SND.UNA + SND.WND
rwnd Receiver Window — espaço livre no buffer do receptor
cwnd Congestion Window — limite imposto pelo controle de congestionamento
effective window min(rwnd, cwnd) — o que realmente limita o envio

A janela efetiva que o remetente pode explorar é min(rwnd, cwnd): ele respeita tanto o receptor quanto a rede.

Diagrama da Janela Deslizante

Bytes:        1000                      4000                  7000
              |-------- enviados -------|---- na janela ------|----- proibido ----|
              ^                        ^                      ^
              SND.UNA                  SND.NXT                SND.UNA + SND.WND
              (próximo ACK esperado)   (próximo a transmitir) (limite da janela)

Quando o ACK 4000 chega, SND.UNA pula para 4000 e toda a janela desliza para a direita, abrindo novos bytes para transmissão.

3. Anúncio da Janela pelo Receptor

O campo Window Size do cabeçalho TCP tem 16 bits. Portanto, sem opções, o receptor só pode anunciar até 65535 bytes (64 KiB) de espaço livre. Em cada segmento que envia (incluindo ACKs puros), o receptor escreve nesse campo o tamanho atual do seu buffer de recepção livre.

TCP Header:
  ...
  Sequence Number: 32 bits
  Acknowledgment Number: 32 bits
  Data Offset + Reserved + Flags
  Window Size: 16 bits   <-- rwnd anunciado
  Checksum: 16 bits
  Urgent Pointer: 16 bits
  Options (variable)

4. Processo de Regulação

  1. Anúncio de Capacidade: O receptor diz ao remetente: "Eu tenho espaço para mais X bytes" (campo Window = X).
  2. Envio Limitado: O remetente mantém a variável cwnd (congestion window) e respeita a regra: Tamanho do Envio = min(rwnd, cwnd). O remetente nunca envia mais dados do que o receptor disse que pode aguentar.
  3. Esvaziamento do Buffer: Quando a aplicação no receptor lê dados do buffer (recv()), espaço é liberado.
  4. Atualização: O receptor envia novos ACKs com o valor atualizado do rwnd, aumentando a janela e permitindo que o remetente acelere novamente.

5. Window Scaling (RFC 7323)

O limite de 64 KiB é severo para enlaces modernos de alta latência (ex: 100 ms RTT, 1 Gbps): em 64 KiB, a taxa máxima seria 5,2 Mbps — ridícula. A solução é o Window Scale Option, negociada no handshake:

  • Durante o SYN, o cliente envia a opção Window Scale: <shift> (1 byte, valor 0-14).
  • Se o servidor também enviar a opção no SYN-ACK, ela está ativa para a conexão.
  • A partir daí, todo valor do campo Window Size é multiplicado por 2^shift.
  • Com shift 14, o limite sobe para 1 GB (65535 × 214 = 1.073.725.440 bytes).
# Verificar se window scaling está ativo (Linux):
sysctl net.ipv4.tcp_window_scaling     # 1 = habilitado (default)

# Em uma captura:
tcpdump -n -i any 'tcp[tcpflags] == tcp-syn' -v
#   ... options [mss 1460,nop,wscale 9,nop,nop,sackOK,TS val-ecri ...

6. O Problema da Janela Zero (Zero Window)

Se a aplicação no receptor estiver muito lenta e o buffer encher completamente, o receptor enviará um rwnd = 0.

  • Bloqueio: O remetente deve parar de enviar novos dados de usuário imediatamente.
  • Manutenção da Conexão: O remetente entra em modo de persistência. Ele envia pequenos segmentos de teste chamados Zero Window Probes (sondas de janela zero) para verificar se o receptor já liberou algum espaço.
  • A primeira sonda é enviada após o tempo máximo de persistência (max persist timer, ~60 s).
  • Em Linux: probes a cada tcp_retries2 (=15) retransmissões, depois aborta.
  • Desbloqueio: Assim que o receptor tiver espaço, ele responde à sonda com um novo rwnd > 0, e o remetente retoma a transmissão normal.

Pegadinha: atualização de janela perdida

Imagine que o receptor libera 1000 bytes e envia um ACK com Window = 1000. Se esse pacote for perdido na rede, o remetente nunca saberá — e ficará parado aguardando indefinidamente. Para evitar esse deadlock, o remetente envia as Zero Window Probes; o receptor, ao respondê-las, reanuncia o rwnd atual.

7. Silly Window Syndrome (SWS)

Outra patologia clássica (descrita na RFC 1122): se o receptor libera 1 byte por vez, ele anuncia Window = 1 repetidamente, e o remetente envia segmentos de 1 byte — desperdiçando 40+ bytes de cabeçalho por byte útil.

A solução é dupla:

  • Clark's Solution (receptor): Não anunciar janelas pequenas. Só enviar Window > 0 quando houver espaço suficiente para um MSS ou para metade do buffer (o que for maior).
  • Nagle's Algorithm (remetente): Não enviar segmentos pequenos se houver dados não confirmados em trânsito — acumular até completar um MSS ou receber ACK.

No Linux:

sysctl net.ipv4.tcp_sack           # SACK
sysctl net.ipv4.tcp_nagle         # 1 = habilita Nagle (default)

8. Diferença Crucial: Fluxo x Congestionamento

Aspecto Controle de Fluxo Controle de Congestionamento
Defende quem? O receptor (buffer) A rede (roteadores)
Variável rwnd (16 bits no header) cwnd (interno, algoritmo)
Quem decide Receptor (anuncia) Remetente (infere por perdas)
Sinal explícito Sim, no header Não, inferido
Reage a Lentidão do receptor Perdas, duplicação de ACKs, ECN

O envio real obedece sempre min(rwnd, cwnd). Se a rede está saudável mas o receptor lento, o gargalo é rwnd; se o receptor está ocioso mas a rede congestionada, o gargalo é cwnd.

9. Exemplo de Evolução da Janela

Buffer receptor de 64 KiB, remetente envia 16 KiB por segmento (janela inicial 65535):

T=0   SND.UNA=1     SND.NXT=16384   Window=65535   (em trânsito: 16383 bytes)
T=10  ACK 16384 chega                Window=65535   (desliza; libera +16384)
T=10  SND.NXT=32768                                 (envia mais 16384)
T=20  aplicação receptora para de ler (recv travado)
T=20  ACK 49152 chega                Window=8192    (só sobrou 8 KiB livre)
T=30  remetente reduz envio a 8192
T=40  aplicação receptora retoma leitura -> próximo ACK: Window=65535 (full)

10. Resumo

A Janela Deslizante é o coração do controle de fluxo TCP. Permite pipelining (envio de múltiplos segmentos sem esperar ACK individual), adapta-se dinamicamente ao consumo do receptor e, combinada com Window Scaling, suporta enlaces de alta banda-delay product. Sintonizar rwnd é tão importante quanto cwnd para o throughput real — em redes rápidas de longa distância, é o rwnd que costuma ditar o limite.


Tip

Em Linux, o tamanho dos buffers TCP é ajustável: sysctl net.ipv4.tcp_rmem (mínimo/default/máximo do buffer de recepção) e net.ipv4.tcp_wmem (envio). Em servidores de alto throughput, valores como 4096 87380 6291456 (default moderno) garantem janelas grandes o suficiente para enlaces de múltiplos Gbps.