Eu corro um programa específico no linux que às vezes falha. Se você abri-lo rapidamente depois disso, ele escutará no soquete 49201 em vez de 49200, como fez na primeira vez. O netstat revela que 49200 está no estado TIME_WAIT.
Existe um programa que você pode executar para forçar imediatamente esse soquete a sair do estado TIME_WAIT?
TIME_WAIT
servidores" , basta pular as três primeiras respostas que evitam a pergunta em vez de respondê-la.Respostas:
Deixe-me elaborar. O TCP (Transmission Control Protocol) foi projetado para ser um protocolo de transmissão de dados bidirecional, ordenado e confiável entre dois pontos finais (programas). Nesse contexto, o termo confiável significa que ele retransmitirá os pacotes se ele se perder no meio. O TCP garante a confiabilidade enviando de volta os pacotes de confirmação (ACK) para um único ou vários pacotes recebidos do par.
O mesmo ocorre com os sinais de controle, como solicitação / resposta de término. O RFC 793 define o estado TIME-WAIT da seguinte maneira:
Consulte o seguinte diagrama de estado TCP:
O TCP é um protocolo de comunicação bidirecional; portanto, quando a conexão é estabelecida, não há diferença entre o cliente e o servidor. Além disso, qualquer um pode chamar encerra e ambos os pares precisam concordar em fechar para fechar completamente uma conexão TCP estabelecida.
Vamos chamar o primeiro a chamar as quits como o ativo mais próximo e o outro o passivo mais próximo. Quando o ativo mais próximo envia FIN, o estado passa para FIN-WAIT-1. Em seguida, ele recebe um ACK para o FIN enviado e o estado passa para FIN-WAIT-2. Depois de receber o FIN também do passivo mais próximo, o ativo mais próximo envia o ACK ao FIN e o estado passa para TIME-WAIT. Caso o passivo mais próximo não tenha recebido o ACK do segundo FIN, ele retransmitirá o pacote FIN.
O RFC 793 define o TEMPO LIMITE para ser o dobro da Vida útil máxima do segmento, ou 2MSL. Como o MSL, o tempo máximo que um pacote pode percorrer na Internet é definido para 2 minutos, 2MSL é de 4 minutos. Como não há ACK para um ACK, o ativo mais próximo não pode fazer nada além de esperar 4 minutos se aderir corretamente ao protocolo TCP / IP, apenas no caso de o remetente passivo não ter recebido o ACK em sua FIN (teoricamente) .
Na realidade, os pacotes ausentes são provavelmente raros e muito raros se tudo estiver acontecendo dentro da LAN ou dentro de uma única máquina.
Para responder à pergunta na íntegra, Como forçosamente fechar um soquete em TIME_WAIT ?, eu ainda ficar com a minha resposta original:
Na prática, eu o programaria para que ele ignore o estado TIME-WAIT usando a opção SO_REUSEADDR como o WMR mencionado. O que exatamente SO_REUSEADDR faz?
fonte
/etc/init.d/networking
é específica da plataforma (Debian?), Portanto a linha de comando precisa será diferente (às vezes radicalmente) para outros sistemas. Concordo com outros comentaristas que isso parece um exagero grave e obviamente perturbador para quaisquer serviços de rede não relacionados.Não sei se você tem o código-fonte desse programa específico em execução, mas se sim, basta definir SO_REUSEADDR através do
setsockopt(2)
qual permite vincular o mesmo endereço local, mesmo que o soquete esteja no estado TIME_WAIT (a menos que tomada está ouvindo ativamente, consultesocket(7)
).Para mais informações sobre o estado TIME_WAIT, consulte as perguntas freqüentes sobre o soquete Unix .
fonte
SO_REUSEADDR
não "fecha" um soquete. Apenas permite reutilizar aqueles que já estão abertos. Portanto, a pergunta ainda é "Como fechar um soquete à forçaTIME_WAIT
?"SO_REUSEADDR
deixarábind()
prosseguir; mas se você quiser ouvir esse soquete,listen()
retornaráEADDRINUSE
o mesmo. Em outras palavras, essa resposta pode ajudar o software cliente a usar portas efêmeras, mas não resolve o problema do software para servidor.Até onde eu sei, não há como forçar o fechamento do soquete fora da gravação de um manipulador de sinal melhor no seu programa, mas existe um arquivo / proc que controla quanto tempo leva o tempo limite. O arquivo é
e você pode definir o tempo limite para 1 segundo fazendo o seguinte:
No entanto, esta página contém um aviso sobre possíveis problemas de confiabilidade ao definir essa variável.
Há também um arquivo relacionado
que controla se os soquetes TIME_WAIT podem ser reutilizados (presumivelmente sem tempo limite).
Aliás, a documentação do kernel avisa que você não deve alterar nenhum desses valores sem 'conselhos / solicitações de especialistas técnicos'. O que eu não sou.
O programa deve ter sido gravado para tentar uma ligação à porta 49200 e depois incrementar em 1 se a porta já estiver em uso. Portanto, se você tiver controle do código-fonte, poderá alterar esse comportamento para aguardar alguns segundos e tentar novamente na mesma porta, em vez de incrementar.
fonte
1
funcionar em conexões futuras, mas e as atuais que já estão abertas?Na verdade, existe uma maneira de matar uma conexão - killcx . Eles afirmam que funciona em qualquer estado da conexão (que eu não verifiquei). Você precisa conhecer a interface em que a comunicação acontece, mas parece assumir eth0 por padrão.
UPDATE: outra solução é o cutter, que vem nos repositórios de algumas distribuições Linux.
fonte
Outra opção é usar a opção SO_LINGER com um tempo limite de 0. Dessa forma, quando você fecha o soquete, é forçado a fechar, enviando um RST em vez de entrar no comportamento de fechamento FIN / ACK. Isso evitará o estado TIME_WAIT e poderá ser mais apropriado para alguns usos.
fonte
Uma solução alternativa seria ter algum software confiável de proxy ou encaminhamento de porta que escute na porta 49200 e, em seguida, encaminhe a conexão para uma das várias instâncias do seu programa menos confiável usando portas diferentes ... O HAPROXY vem à mente.
Aliás, a porta em que você está se conectando é bastante alta. Você pode tentar usar um não usado logo acima do intervalo de 0 a 1024. É menos provável que seu sistema use um número de porta menor como uma porta efêmera.
fonte
TIME_WAIT é o problema mais comum na arquitetura de servidor cliente de programação de soquete. Aguarde alguns segundos, tentando periodicamente é a melhor solução para isso. Para aplicativos em tempo real, eles precisam que o servidor seja levantado imediatamente. Existe a opção SO_REUSEADDR para eles.
fonte