(Transmission Control Protocol)
O TCP é um protocolo de rede que fica na camada de transporte do modelo OSI. Ele é orientado à conexão e confiável, significando que todas as comunicações, antes de iniciar a troca de dados, precisam estabelecer uma conexão. Esse estabelecimento ocorre pelo three-way handshake. Esse protocolo, também, corrige erros como perda, duplicação ou falta de integridade de segmentos, envia segmentos confirmando o recebimento dos dados, faz controle de congestionamento e de fluxo. Além disso tudo, faz a sincronização dos segmentos e finalização das conexões.
O segmento TCP é composto por um cabeçalho que pode variar de 20 à 60 bytes. Essa variação ocorre devido ao campo options, onde dependendo das opções usadas, o tamanho do cabeçalho TCP pode mudar. A seguir é apresentado o segmento TCP e em seguida o conceito de cada campo, sendo realizada uma síntese de acordo com Soares, Lemos e Colcher (1995); Tanenbaum (1997); Diógenes (2004); Comer (1998); Firewall.cx [200-?]; Postel (1981c):
Fonte: Postel (1981c, p. 15) adaptado.
- Source port: contém um número que corresponde a porta de origem utilizada para o envio de segmentos TCP. Este campo é de 16 bits;
- Destination port: contém um número que corresponde a porta de destino utilizada para o recebimento de segmentos TCP. Este campo é de 16 bits;
- Sequence number: identifica a posição do segmento no fluxo de transmissão dos segmentos enviados. Visto que quando os segmentos chegam ao destino podem estar totalmente desordenados. O receptor também pode saber através desse campo se um segmento foi perdido ou duplicado. Este campo é de 32 bits;
- Acknowledgement number: especifica o campo sequence number do próximo segmento que deve ser enviado. Em outras palavras, sempre descreve qual deve ser o número de seqüência do próximo segmento que uma estação espera receber. O transmissor também pode saber através desse campo se um segmento foi perdido. Quando esse campo é significativo a flag ACK deve estar setada com o valor 1. Este campo é de 32 bits;
- Data offset: também conhecido como Header Length (RFC 3168), contém o tamanho do cabeçalho TCP. Esse campo é necessário, pois o campo Options varia de comprimento de acordo com as opções usadas. Este campo é de 4 bits, o que representa 16 números em decimal, assim ele pode variar de 0 à 15 (0000 à 1111). Só que cada número nesse campo é equivalente a uma DWord (Double Word) que é igual a 4 bytes. Então, para cada valor desse campo se deve multiplicar por 4 bytes. Ex: se o campo contiver 8, então o tamanho do cabeçalho é 8x4 que é igual a 32 bytes. O tamanho mínimo de um cabeçalho TCP é 20 bytes (não incluindo opções). Com isso, o campo Data offset deve ser no mínimo 5, pois 5x4 é igual a 20. Caso se utilize opções, o tamanho máximo que poderá alcançar é 60 bytes, pois 15x4 é igual a 60;
- Reserved: reservado para uso futuro. Este campo é de 6 bits;
- Flags ou Control Bits: especifica a intenção do segmento para que ele possa ser manuseado corretamente pelo destino. Este campo é de 6 bits. Veja a seguir as funções:
- URG: flag que indica urgência, priorizando segmentos. Também, indica que o campo urgent pointer é relevante (significativo) e que existem dados urgentes no segmento,
- ACK: esta flag especifica que o campo acknowledgement number é significativo, sendo que os dois (esta flag e o campo acknowledgement number), indiretamente, confirmam a recepção de segmentos. Essa flag pode não só confirmar o recebimento para o transmissor, mas também pode significar um pedido de retransmissão. Isso ocorrerá quando um segmento é perdido/descartado e o transmissor recebe um segundo pedido do receptor. O receptor refaz o pedido depois de um tempo determinado se não houver uma resposta. Nesse caso o transmissor fará uma retransmissão,
- PSH: flag que indica que o receptor deve entregar os dados a aplicação no momento da sua chegada, ao invés de armazená-lo em um buffer e esperar que esse buffer se complete para depois, entregar o seu conteúdo à aplicação,
- RST: flag que aponta a impossibilidade de uma conexão. Em outras palavras, é expedida de forma automática pelo receptor como resposta de um segmento anteriormente enviado, apontando que não existe um serviço para responder,
- SYN: flag que é usada no pedido inicial do estabelecimento de uma conexão. Caso esse pedido seja aceito, então é usada para iniciar a sincronização dos números de seqüência,
- FIN: flag que finaliza uma conexão, mostrando que não há mais dados para serem enviados,
- Window: também conhecido como Window Size, indica ao transmissor qual a capacidade do buffer do receptor, ou seja, quantos bytes de cada vez o transmissor pode enviar para que só então uma confirmação (TCP-ACK) seja enviada pelo receptor. Na prática, essa quantidade de bytes é equivalente a um ou mais segmentos TCP consecutivos emitidos em seqüência. Quando esse campo é zero, significa que quem o enviou está com sua capacidade de buffer esgotada e que o transmissor deve aguardar, não enviando mais dados, até que um outro segmento seja transmitido com este mesmo campo diferente de zero. Este campo é de 16 bits;
- Checksum: verifica a integridade do segmento TCP e de seu pseudo cabeçalho. Este campo é de 16 bits;
- Urgent pointer: quando há dados urgentes dentro do campo data, a flag URG deve estar setada com o valor um. O campo urgent pointer indica o endereço do último byte dos dados urgentes em um segmento, ou seja, mostra onde terminam os dados urgentes dentro do campo data. Este campo é de 16 bits;
- Options: aumenta a capacidade do segmento, introduzindo novas características. A quantidade de bits ocupada por este campo é variável, dependendo das opções utilizadas. A seguir são expostas algumas dessas opções:
- MSS (Maximum Segment Size): determina o tamanho máximo dos dados de um segmento TCP com o intuito de evitar a fragmentação ou a subutilização do datagrama IP na rede de destino. O valor do MSS é especificado no campo options do cabeçalho TCP durante o estabelecimento de uma conexão, utilizando as flags SYNs para isto. O intuito de quem o transmitiu é dizer qual é o tamanho máximo de dados em um único segmento que ele pode receber. Se estiver utilizando o Ethernet 2, o tamanho máximo do MSS é 1460 bytes, pois este protocolo da camada de enlace pode ter no máximo 1500 bytes de dados. Ao se subtrair os cabeçalhos mínimos do IP e TCP que são 40 bytes, então se chegará a 1460 bytes. O MSS ocupa 4 bytes do campo options (man iptables -> TCPMSS),
- SACK permitted (Selective ACK permited): esta opção, também, é definida durante o estabelecimento da conexão nas flags SYNs quando a camada de transporte nos dois lados da conexão informam que desejam utilizar o SACK,
- SACK (Selective ACK): durante a troca de dados, se alguma confirmação (TCP-ACK) for duplicada, indicando descarte de segmentos ou atraso (não é necessário receber três ACKs duplicados), esta opção se encarregará de apontar qual ou quais segmentos podem precisar ser retransmitidos. Só existirá esta opção se o SACK permitted for habilitado durante a fase de estabelecimento da conexão,
- Padding: enchimento variável que assegura que o comprimento do cabeçalho TCP seja múltiplo inteiro de 32 bits. Vale ressaltar que é preenchido com zeros. A quantidade de bits ocupada por esse campo é variável dependendo das opções utilizadas no campo Options;
- Data: dados que são fornecidos para a camada de aplicação onde eventualmente existe uma aplicação esperando por eles;
As especificações do TCP foram atualizadas em setembro de 2001 de acordo com a RFC (Request for Comments) 3168. Esta atualização teve o intuito de melhorar o desempenho do protocolo em relação ao descarte de pacotes quando a rede está congestionada. Um congestionamento de rede ocorre quando o desempenho dos roteadores, que estão entre os hosts finais, é prejudicado pelo excesso de pacotes na rede. Muitas são as causas de congestionamento nos roteadores, como por exemplo: processador lento, pouca memória, muita memória, muitas interfaces de rede de entrada e uma única de saída, largura de banda mal dimensionada, imposição do transmissor etc. Na figura a seguir é mostrado o que mudou no cabeçalho TCP:
Fonte: Ramakrishnan, Floyd e Black (2001, p. 13) adaptado.
Como pode ser visto na figura 2, o campo Reserved diminuiu e duas novas flags foram acrescentadas no cabeçalho TCP que são as CWR e ECE:
- CWR (Congestion Window Reduced): flag que reduz a quantidade de dados em trânsito, ou seja, o transmissor mostra ao receptor que está reagindo contra o congestionamento que foi detectado. Também, é utilizada pelo transmissor para indicar ao receptor que houve o recebimento de um segmento TCP com flag ECN-Echo ligada e que ele deve parar de enviar TCP-ACKs com essas flags;
- ECE ou ECN-Echo (Expliced Congestion Notification Echo): é enviada, junto com um ACK, pelo receptor ao transmissor para especificar que está havendo congestionamento na rede. O receptor sabe que houve congestionamento quando ele recebe um datagrama de um roteador com o ECN-CE (ECN-Congestion Experienced) setado indicando que está havendo congestionamento na rede;
Quando ocorre um congestionamento, é indício que pacotes estão sendo descartados. Stevens (1997, p. 2) complementa, descrevendo que este descarte é devido a capacidade de algum ponto da Internet ter sido alcançado. Os hosts finais podem saber que isto está acontecendo por três fatores: timeout de segmento sem confirmação (TCP-ACK), recebimento de três segmentos TCP-ACKs duplicados ou notificação explícita de congestionamento (TCP-ECN-Echo). No momento em que um congestionamento é detectado, o transmissor reduz a taxa de transmissão e reenvia o(s) segmento(s) que foram descartados.
Para um melhor entendimento sobre controle de congestionamento com o TCP, se faz necessário abordar assuntos que envolvem o próprio TCP. Assim, nos três tópicos a seguir são expostos assuntos como: estabelecimento de conexão, troca de dados, janelamento, retransmissão, controle de fluxo, controle de congestionamento etc.
(Notificação Implícita de Congestionamento)
Ao se usar o TCP é necessário estabelecer uma conexão antes da troca de dados. Esse estabelecimento de conexão se chama Three-way Handshake e são utilizados três segmentos para isto. Assim, para estabelecer uma conexão o receptor deve enviar um TCP-SYN para o transmissor, o transmissor responde com um TCP-SYN-ACK e o receptor envia um TCP-ACK. Diógenes (2004, p. 84) evidência que o Three-way Handshake consiste de três trocas de informações que são um SYN, SYN/ACK e ACK. Esses segmentos são usados para que os hosts finais saibam da existência um do outro e para que troquem informações como: porta de origem e de destino pretendidas, números de seqüência inicias, janelas iniciais, tamanho máximo de um segmento, tipo de implementação para controle de congestionamento etc. Com isso, é estabelecido uma conexão entre o transmissor e o receptor. Devido as essas características apresentadas, o TCP é chamado de orientado à conexão.
A partir deste momento, o transmissor pode trocar dados com o receptor. Para cada segmento enviado, tanto pelo transmissor, quanto pelo receptor, se faz necessário uma confirmação com um segmento TCP com a flag ACK ligada. No entanto, enquanto essa confirmação não chegar, o destino não pode enviar os segmentos seguintes. Comer (1998, p. 214) assinala que o transmissor espera uma confirmação antes de enviar o próximo segmento. Essa confirmação vem para garantir que o segmento transmitido chegou ao seu destino de forma correta. É interessante frisar que o único segmento TCP que não tem a flag ACK ligada é o primeiro (TCP-SYN) enviado pelo receptor durante o estabelecimento de uma conexão. Devido as características acima, o TCP é chamado de confiável.
Quando os hosts finais trocam dados, o TCP utiliza o conceito de janela deslizante que tem o intuito de aproveitar ao máximo a capacidade dos recursos oferecidos tanto pela rede, quanto pelo receptor. Como já foi dito, para cada segmento TCP enviado, se faz necessário uma confirmação (TCP-ACK). Isso, em termos de confiabilidade é interessante, mas de desempenho não. Pensando nisto, o TCP traz o recurso da janela deslizante, onde as confirmações só serão enviadas depois de certa quantidade de bytes transferidos. Em outras palavras, isso significa que uma confirmação só será enviada depois que um ou vários segmentos forem transmitidos. Comer (1998, p. 216) escreveu que a janela deslizante permite que múltiplos segmentos sejam transmitidos antes de esperar uma confirmação. Com isso, o desempenho geral do protocolo aumenta, pois ele não tem que esperar por uma confirmação para enviar vários segmentos consecutivos. Vale ressaltar que o número de segmentos que pode ser enviado de uma única vez é limitado pela quantidade de bytes definida pela janela de transmissão. Para saber o valor dessa janela de transmissão, o TCP verifica dois parâmetros: a AWND (Advertised Window ou Announced Window) e a CWND (Congestion Window).
A AWND é uma propaganda ou janela, enviada pelo receptor ao transmissor, da quantidade de bytes que aquele pode receber em seu buffer de uma única vez. Esse parâmetro é definido no campo window do cabeçalho TCP. Ele tem o intuito de aproveitar ao máximo a capacidade do receptor sem que o transmissor envie mais bytes que aquele é capaz de suportar e que, também, a capacidade dele não seja subutilizada. Os valores da AWND são especificados desde o estabelecimento, até a finalização de uma conexão. A AWND, também, é conhecida como RWND (Receiver Window) de acordo com a RFC 2581. As características apresentadas acima da AWND, são conhecidas como controle de fluxo.
Já a CWND pode ser entendida como uma variável cujo conteúdo é capacidade passageira de transferência de bytes pela rede. Algoritmos de controle congestionamento adicionam a CWND como uma nova janela para o transmissor, sendo o concorrente direto da AWND (campo window do cabeçalho TCP). Na prática, a CWND pode ser entendida como a quantidade de bytes que os roteadores podem suportar sem que haja congestionamento, evitando assim o descarte de datagramas. Para uma melhor compreensão, Stevens (1997, p. 2) considera que a AWND é o controle de fluxo imposto pelo receptor e a CWND é o controle de fluxo imposto pela rede através do transmissor. Nada adiantaria, por exemplo, se o buffer de um receptor (AWND) fosse de 10 bytes, o da rede (CWND) fosse 4 bytes e o transmissor enviasse um segmento compondo 10 bytes. A rede não suportaria e o descartaria. O inverso também é verdadeiro, se a rede suporta 10 bytes, o receptor somente 4 bytes e se o transmissor enviasse 10 bytes, o receptor não teria buffer para armazenar o segmento. Devido a esse problema, o transmissor sempre escolhe o mínimo entre a AWND e a CWND que no exemplo exposto seria uma janela de 4 bytes.
Para saber o valor da AWND é fácil, pois quem o anuncia é o próprio receptor que sabe de sua capacidade atual, mas para calcular a CWND não é tão simples. Isso, porque o transmissor precisa conhecer a capacidade da rede que são equipamentos que estão remotamente conectados. Para dificultar um pouco mais, a capacidade desses equipamentos pode variar no decorrer do tempo, sendo que essa variável deve ser atualizada freqüentemente. Para realizar a descoberta da janela de congestionamento são utilizados vários algoritmos como: Slow-Start, Congestion Avoidance, Fast Retransmit e Fast Recovery. Além desses algoritmos, também, são utilizadas várias versões do TCP como: Tahoe, Reno, New Reno e SACK.
Durante o estabelecimento de uma conexão, são especificados os valores iniciais para a AWND e a CWND. O valor de AWND é anunciado pelo transmissor e pelo receptor no campo window do cabeçalho TCP. A CWND não tem campo, devido a isso, é criada essa variável pelo algoritmo chamado Slow-Start com o valor inicial a de um MSS (Maximum Segment Size) que, em outras palavras, é similar (equivalente) a um segmento. De acordo com Tanenbaum (1997, p. 612) quando uma conexão é estabelecida, o transmissor ajusta a janela de transmissão ao tamanho de um MSS. O MSS é especificado durante o estabelecimento da conexão nas opções do cabeçalho TCP. Depois do estabelecimento da conexão, ou seja, durante a troca de dados, a AWND ainda continua sendo fornecida dinamicamente pelo hosts finais. Já no caso da CWND, são usados vários algoritmos para a sua regulação.
Durante a troca de dados, o algoritmo Slow-Start aumenta exponencialmente a janela de congestionamento (CWND). Ao enviar um segmento e receber uma confirmação, a CWND passa de um segmento para dois. Quando esses dois segmentos são enviados e confirmados, a CWND passa para 4 segmentos e assim sucessivamente até alcançar o valor de AWND que é o limite. Vale relembrar que a janela de transmissão é o mínimo entre a AWND e a CWND. Essa situação demonstrada de crescimento exponencial seria o ideal, pois a rede estaria suportando a quantidade de bytes da janela do receptor. Mas na prática, isso poderia ser diferente caso a CWND não pudesse alcançar tal valor. Nesse caso, usam-se outros algoritmos que evitam congestionamento da rede. Um congestionamento de rede ocorre pela incapacidade de equipamentos entre os hosts finais de processar todos os pacotes que passam por eles. Existem duas maneiras implícitas para saber se está havendo congestionamento na rede.
A primeira é pela expiração do RTT (Round Trip Time). O RTT é uma estimativa de tempo gasta para que um segmento seja enviado e confirmado, ou seja, tempo de ida e de volta. Para cada segmento enviado, esse temporizador é iniciado. Comer (1998, p. 230) explica que se esse temporizador terminar antes da confirmação do segmento, o TCP retransmite o segmento não confirmado. Mas antes de fazer essa retransmissão, entra em ação um outro algoritmo chamado de Congention Avoidance o qual encara a expiração do RTT como perda de pacote. Esse algoritmo utiliza uma outra variável chamada de SSTHRESH (Slow-Start Threshold Size) que no momento da detecção de congestionamento é atribuído a ela o valor da metade da quantidade de bytes da janela de transmissão atual [SSTHRESH = mínimo(AWND,CWMD) / 2]. Depois de definido o valor para o SSTHRESH, o algoritmo diminui a CWND para um segmento (CWND = 1 segm). Então, é executado o Slow-Start para reiniciar a transmissão, retransmitir o segmento descartado e os subseqüentes. Agora, o crescimento exponencial da CWND tem um limite que é o valor do SSTHRESH. Ao alcançar esse limite, o crescimento exponencial passa para linear, significando que é aumentada de um segmento a cada RTT.
A segunda maneira para saber se está havendo congestionamento implicitamente na rede é pela recepção de três TCP-ACKs duplicados. No receptor é executado o algoritmo chamado Fast Retransmit que ao receber três TCP-ACKs duplicados, é encarado como perda de segmento. Três ACKs duplicados querem dizer, três confirmações de segmentos já enviados com o valor do campo acknowledgement number iguais. Stevens (1997, p. 4) detalha que um ou dois ACKs duplicados são considerados segmentos fora de ordem, mas três ou mais é um forte indício de descarte. Devido a isso, depois dessas três confirmações duplicadas, o algoritmo Fast Retransmit imediatamente retransmite o segmento solicitado no campo duplicado, não esperando a expiração do RTT. Caso não haja mais descarte, essa confirmação do recebimento da retransmissão deve confirmar a recepção de todos os outros segmentos anteriormente enviados. Em seguida, entra em ação o algoritmo Fast Recovery que atribui ao SSTHRESH a metade da janela de congestionamento (SSTHRESH = CWMD / 2) que não pode ser menos que dois segmentos. Já a janela congestionamento é SSTHRESH mais três vezes o valor de um segmento (CWND = SSTHRESH + 3 segm). Esta multiplicação por três é devido ao congestionamento não ser severo, pois foram recebidos três reconhecimentos duplicados que afirmam que o receptor recebeu três segmentos com sucesso. Após todos esses procedimentos, o algoritmo Congestion Avoidance é executado para reiniciar a transmissão normal dos segmentos.
(Notificação Explícita de Congestionamento)
O estabelecimento de conexão descrita no tópico anterior é para uma situação normal onde os hosts controlam o congestionamento implicitamente. Mas se os hosts tiverem a intenção de fazê-lo explicitamente devem utilizar tanto a flag ECE (ECN-Echo), quanto a CWR (Congestion Window Reduced). Ramakrishnan, Floyd e Black (2001, p. 13) explanam que a notificação explícita de congestionamento utilizam duas novas flags dentro do campo Reserved do cabeçalho do segmento TCP. Durante o estabelecimento de uma conexão com controle de congestionamento explícito, o receptor envia um TCP-SYN-ECN-CWR para o transmissor, o transmissor deve responder com um TCP-SYN-ACK-ECN e o receptor envia um TCP-ACK. Estes segmentos, além de serem usados para a troca normal de informações, também especificam que o transmissor e receptor estão hábitos a realizarem o controle de congestionamento explícito.
Além dessas duas novas flags no cabeçalho TCP, também são utilizados 2 bits no cabeçalho do datagrama IP. No campo Differentiated Services Field são utilizadas duas flags: o ECT (ECN-Capable Transport) e o ECN-CE (ECN-Congestion Experienced). Ramakrishnan, Floyd e Black (2001, p. 14) mostram que a notificação de congestionamento explícita usa o ECT e o ECN-CE no cabeçalho IP. Durante a troca de dados, o transmissor emite segmentos com o flag ECT no cabeçalho IP ligada. Assim, os roteadores, que estão no meio da transmissão, têm condições de saber se os equipamentos finais estão utilizando controle de congestionamento explicitamente na camada de transporte. Ao descartar datagramas com esta flag ECT ligada, o roteador, que possui esse recurso, envia um datagrama IP para o receptor com a flag ECE ligada. Com isso, mostra ao receptor que houve congestionamento. Os TCP-ACKs seguintes, o receptor manda com a flag ECN-Echo setada para que o transmissor tome as providências para resolver o problema. O transmissor ao receber esses reconhecimentos (confirmações) com ECN-Echo. reduz os valores de CWND e SSTHRESH, passando a enviar os segmentos seguintes com o bit CWR ligado para que o receptor saiba que providências estão sendo tomadas e para que ele pare de enviar TCP-ACKs com ECN-Echo. Para um melhor ententimento sobre o ECT e ECN-CE, leia a parte do Differentiated Services Field no artigo chamado IP ou IPv4 (Internet Protocol ou Internet Protocol versão 4).
Umas das versões do protocolo TCP é o Reno que utiliza os algoritmos Slow-Start, Congestion Avoidance, Fast Retransmit e Fast Recovery. O Reno tenta prevenir o congestionamento através de TCP-ACKs duplicados. Caso receba 3 ACKs duplicados é transmitido novamente o segmento descartado e reduzida a janela de transmissão, conforme já exposto nos tópicos anteriores. O receptor ao receber a retransmissão, deve confirmar sua chegada ao transmissor, transmitindo um TCP-ACK, o qual pode confirmar, também, todos os outros segmentos anteriormente enviados. Mas o Reno de acordo com Costa (2004, p. 1) não trabalha bem com a perda de segmentos consecutivos, reduzindo abruptamente a vazão. O problema nesta versão ocorre quando mais de um segmento é descartado na mesma janela de transmissão. O transmissor vendo isso, irá reduzir a janela sucessivas vezes a cada detecção de segmento descartado, até que todos os segmentos sejam confirmados.
Para resolver esse problema, um nova versão do TCP Reno surgiu: o New Reno. Ao detectar que mais de um segmento em uma mesma janela de transmissão foram descartados, ele deve permanecer no Fast Retransmit e transmitir novamente um segmento descartado a cada solicitação (TCP-ACK duplicado). Isso irá acontecer até que o transmissor receba um TCP-ACK que confirme todos os segmentos enviados até o momento. Assim, evita-se as seguidas reduções na janela de transmissão. Depois, ele sai do algoritmo Fast Retransmit e segue o caminho normal de uma transmissão com o Fast Recovery.
Para melhorar ainda mais o desempenho nas retransmissões é usado atualmente a versão SACK (Selective ACK) do TCP. Que conforme já foi exposto, é utilizado o campo Options do cabeçalho TCP para informar qual ou quais segmentos precisam ser retransmitidos. Mathis, Mahdavi, Floyd e Romanow (1996, p. 2) acrescentam que sem o uso do SACK o transmissor tem que esperar o tempo de ida e volta dos segmentos para saber quais foram perdidos. Somente para termos de conhecimento, a primeira versão do TCP era chamada de Tahoe e utilizava somente os algoritmos Slow-Start e Congestion Avoidance para controle de congestionamento.