Eu sei que há algumas perguntas de SE sobre isso, e acredito que li tantas delas quanto for importante antes de chegar a este ponto.
Por "lado do servidor TIME_WAIT
", quero dizer o estado de um par de soquetes do lado do servidor que teve seu close() iniciado no lado do servidor.
Muitas vezes vejo estas afirmações que me parecem contraditórias:
- O lado do servidor
TIME_WAIT
é inofensivo - Você deve projetar seus aplicativos de rede para que os clientes iniciem close(), fazendo com que o cliente assuma o
TIME_WAIT
A razão pela qual considero isso contraditório é porque TIME_WAIT
no cliente pode haver um problema - o cliente pode ficar sem portas disponíveis, então, em essência, o que foi dito acima é recomendar transferir a carga TIME_WAIT
para o lado do cliente, onde pode haver problema, do lado do servidor onde não há problema.
TIME_WAIT
É claro que o lado do cliente é um problema apenas para um número limitado de casos de uso. A maioria das soluções cliente-servidor envolveria um servidor e muitos clientes, os clientes geralmente não lidam com um volume de conexões alto o suficiente para que isso seja um problema e, mesmo que o façam, há uma série de recomendações para "sanamente" ( ao contrário SO_LINGER
do tempo limite 0 ou da interferência com tcp_tw sysctls), combata o lado do cliente TIME_WAIT
evitando criar muitas conexões muito rapidamente. Mas isso nem sempre é viável, por exemplo, para classes de aplicações como:
- sistemas de monitoramento
- geradores de carga
- procuradores
Por outro lado, eu nem entendo como o lado do servidor TIME_WAIT
é útil. A razão TIME_WAIT
está aí, porque evita a injeção TCP
de fragmentos obsoletos em fluxos aos quais eles não pertencem mais. Para o lado do cliente, TIME_WAIT
isso é feito simplesmente impossibilitando a criação de uma conexão com os mesmos ip:port
pares que essa conexão obsoleta poderia ter (os pares usados são bloqueados por TIME_WAIT
). Mas para o lado do servidor, isso não pode ser evitado, pois o endereço local terá a porta de aceitação, e sempre será o mesmo, e o servidor não pode (AFAIK, só tenho a prova empírica) negar a conexão simplesmente porque um peer de entrada criaria o mesmo par de endereços que já existe na tabela de soquetes.
Eu escrevi um programa que mostra que o TIME-WAIT do lado do servidor é ignorado. Além disso, como o teste foi feito em 127.0.0.1, o kernel deve ter um bit especial que informa se é do lado do servidor ou do lado do cliente (caso contrário, a tupla seria a mesma).
Fonte:http://pastebin.com/5PWjkjEf, testado no Fedora 22, configuração de rede padrão.
$ gcc -o rtest rtest.c -lpthread
$ ./rtest 44400 s # will do server-side close
Will initiate server close
... iterates ~20 times successfully
^C
$ ss -a|grep 44400
tcp TIME-WAIT 0 0 127.0.0.1:44400 127.0.0.1:44401
$ ./rtest 44500 c # will do client-side close
Will initiate client close
... runs once and then
connecting...
connect: Cannot assign requested address
Portanto, para o lado do servidor TIME_WAIT
, as conexões exatamente no mesmo par de portas poderiam ser restabelecidas imediatamente e com sucesso, e para o lado do cliente TIME-WAIT
, na segunda iteração connect()
falharam justamente
Para resumir, a questão é dupla:
- O lado do servidor
TIME_WAIT
realmente não faz nada e fica assim porqueRFC
exige? - A razão pela qual a recomendação é que o cliente inicie close() porque o servidor
TIME_WAIT
é inútil?
Responder1
EmTCPtermos lado do servidor aqui significa o host que possui o soquete no estado LISTEN.
RFC1122permite que o soquete no estado TIME-WAIT aceite nova conexão com algumas condições
When a connection is closed actively, it MUST linger in TIME-WAIT state for a time 2xMSL (Maximum Segment Lifetime). However, it MAY accept a new SYN from the remote TCP to reopen the connection directly from TIME-WAIT state, if it:
Para obter detalhes exatos sobre as condições, consulte oRFC1122. Eu esperaria que também houvesse um OPEN passivo correspondente no soquete (soquete no estado LISTEN).
Active OPEN (chamada de conexão do lado do cliente) não possui tal exceção e deve dar erro quando o soquete estiver em TIME-WAIT, conformeRFC793.
Meu palpite para a recomendação no cliente (em termos de TCP, o host executando OPEN ativo, ou seja, conexão) iniciado próximo é praticamente o mesmo que o seu, que no caso comum ele espalha os soquetes TIME-WAIT em mais hosts onde há abundância de recursos para as tomadas. No caso comum, os clientes não enviam SYN que reutilizaria soquetes TIME-WAIT no servidor. Concordo que a aplicação dessa recomendação ainda depende do caso de uso.
Responder2
O cliente usará um novo TCP ISN (número de sequência inicial) baseado em um algoritmo (incrementado em 1 aproximadamente a cada 4 microssegundos), e o ISN é basicamente sempre maior que o número de sequência enviado no último soquete TCP "ip:port pair" FIN, então o servidor sempre aceitará o novo SYN mesmo que o "par ip:port" ainda esteja registrado no estado TIME_WAIT no servidor.
RFC 793 [RFC0793] suggests that the choice of the ISN of a connection
is not arbitrary, but aims to reduce the chances of a stale segment
from being accepted by a new incarnation of a previous connection.
RFC 793 [RFC0793] suggests the use of a global 32-bit ISN generator
that is incremented by 1 roughly every 4 microseconds.
Responder3
Esseé provavelmente o exemplo mais claro do que o TIME-WAIT realmente faz e, mais importante, por que é importante. Também explica por que evitar algumas dicas de 'especialistas' em máquinas Linux para 'reduzir' o TEMPO DE ESPERA.
Responder4
Você nunca pode ter certeza, com um protocolo não confiável, de que recebeu a última mensagem do seu dispositivo peer; portanto, é perigoso presumir que seu peer desligou o telefone repentinamente. Uma grande desvantagem do protocolo TCP é que apenas cerca de 65.000 portas podem ser abertas simultaneamente. Mas a maneira de superar isso seria migrar para um farm de servidores, que se adapta melhor à carga, do que reciclar rapidamente os números das portas. No final do cliente, é altamente improvável que você fique sem portas se for uma estação de trabalho básica.