Como faço para remover uma conexão de soquete CLOSE_WAIT

92

Escrevi um pequeno programa que interage com um servidor em uma porta específica. O programa funciona bem, mas:

Uma vez que o programa foi encerrado inesperadamente, e desde então essa conexão de soquete é mostrada no CLOSE_WAITestado. Se eu tento executar um programa, ele trava e tenho que forçar o fechamento, o que acumula ainda mais CLOSE_WAIT conexões de soquete.

Existe uma maneira de liberar essas conexões?

Dilletante
fonte
4
Você não pode (e não deve). CLOSE_WAIT é um estado definido pelo TCP para conexões sendo fechadas esperando que a contraparte reconheça isso.
vonbrand,
1
Veja também unix.stackexchange.com/questions/10106/… ... que não vou votar como uma duplicata, porque isso encerraria a questão como fora do tópico.
derobert de
4
@vonbrand Não, é exatamente o contrário. É o estado de uma conexão que já foi fechada pelo par e está aguardando que o aplicativo local feche seu final.
user207421
Se você estiver usando Commons HttpClient, nuxeo.com/blog/… tem muitas informações relevantes. Do RFC 2616, Seção 14: Aplicativos HTTP / 1.1 que não suportam conexões persistentes DEVEM incluir a opção de conexão "fechar" em todas as mensagens.
Mayank Ahuja

Respostas:

80

CLOSE_WAITsignifica que seu programa ainda está em execução e não fechou o soquete (e o kernel está esperando por isso). Adicione -pa netstatpara obter o pid e, em seguida, mate-o com mais força (com SIGKILLse necessário). Isso deve acabar com suas CLOSE_WAITtomadas. Você também pode usar pspara localizar o pid.

SO_REUSEADDRé para servidores e TIME_WAITsockets, portanto, não se aplica aqui.

Derobert
fonte
2
bem ... matar o processo pode não ser o melhor se aquele programa abrir muita conexão, apenas alguns dos que ficam em "CLOSE_WAIT": nesse caso matar o processo pode ser completamente impossível ou impróprio (o programa ainda funciona e fornece serviços, com essas outras ligações). Apenas fechar a conexão pendente seria muito mais apropriado. mas na verdade é geralmente o próprio programa que não fecha localmente o connectino (CLOSE_WAIT significa que recebeu 'FIN' da outra extremidade e o programa apenas tem que fechar a conexão localmente). Um relatório de bug pode ser apropriado
Olivier Dulac
41

Conforme descrito por Crist Clark .

CLOSE_WAIT significa que a extremidade local da conexão recebeu um FIN da outra extremidade, mas o sistema operacional está aguardando que o programa na extremidade local realmente feche sua conexão.

O problema é que o programa em execução na máquina local não está fechando o soquete. Não é um problema de ajuste do TCP. Uma conexão pode (e muito corretamente) permanecer em CLOSE_WAIT para sempre enquanto o programa mantém a conexão aberta.

Uma vez que o programa local fecha o socket, o SO pode enviar o FIN para a extremidade remota que faz a transição para LAST_ACK enquanto você espera pelo ACK do FIN. Assim que for recebido, a conexão é finalizada e cai da tabela de conexão (se o seu final estiver em CLOSE_WAIT, você não terminará no estado TIME_WAIT).

user2618402
fonte
4
como fechar o soquete ??
Divyang Shah
1
Você fecha a alça que você tem no soquete que você abriu. Use close()ou closesocket(), dependendo de qual plataforma você está usando.
Remy Lebeau
8

Também estou tendo o mesmo problema com um servidor Tomcat mais recente (7.0.40). Ele fica sem resposta uma vez por alguns dias.

Para ver as conexões abertas, você pode usar:

sudo netstat -tonp | grep jsvc | grep --regexp="127.0.0.1:443" --regexp="127.0.0.1:80" | grep CLOSE_WAIT

Conforme mencionado neste post , você pode usar /proc/sys/net/ipv4/tcp_keepalive_timepara visualizar os valores. O valor parece estar em segundos e o padrão é 7200 (ou seja, 2 horas).

Para alterá-los, você precisa editar /etc/sysctl.conf.

Open/create `/etc/sysctl.conf`
Add `net.ipv4.tcp_keepalive_time = 120` and save the file
Invoke `sysctl -p /etc/sysctl.conf`
Verify using `cat /proc/sys/net/ipv4/tcp_keepalive_time`
Amil Waduwawara
fonte
4
a resposta é confusa. você disse que os estados de não resposta desapareceram por vários dias ... mas depois também tentou definir o tempo de manutenção de funcionamento para apenas 120 segundos. mesmo com o valor padrão (7200 seg), não deve durar vários dias, certo?
fanchyna de
8

Embora muitas conexões CLOSE_WAIT signifiquem que há algo errado com seu código no início e isso não é uma boa prática aceita.

Você pode querer verificar: https://github.com/rghose/kill-close-wait-connections

O que este script faz é enviar o ACK que a conexão estava esperando.

Isto é o que funcionou para mim.

miragem
fonte
você envia ação para fechar-esperar soquete. com não funciona .. se funciona, por quê?
Chinaxing
Estou supondo que o sistema operacional já enviou o FIN para o host remoto. O host remoto provavelmente não pode responder com o ACK que o soquete está esperando.
miragem
sim, isso mesmo (do código do kernel). mas também tenho dúvidas sobre o SEQ do pacote que você envia, que é "10", o kernel não verifica?
Chinaxing
Provavelmente não. Acho que tentei com muitos números aleatórios e eles pareceram funcionar.
mirage
5

Você pode fechar soquetes à força com o sscomando; o sscomando é uma ferramenta usada para despejar estatísticas de soquete e exibe informações de maneira semelhante (embora mais simples e rápida) ao netstat.

Para matar qualquer socket no estado CLOSE_WAIT, execute isto (como root)

$ ss --tcp state CLOSE-WAIT --kill
Mustapha Hadid
fonte
Essa deve ser a melhor resposta.
Tom
3

Deve ser mencionado que a Socketinstância tanto no cliente quanto na extremidade do servidor precisa ser chamada explicitamente close(). Se apenas uma das extremidades invocar close(), o socket permanecerá no estado CLOSE_WAIT.

Binita Bharati
fonte
1

Também é importante notar que, se seu programa gerar um novo processo, esse processo pode herdar todos os identificadores abertos. Mesmo após o término do seu próprio programa, esses identificadores herdados ainda podem estar vivos por meio do processo filho órfão. E eles não aparecem necessariamente da mesma forma no netstat. Mas mesmo assim, o soquete ficará em CLOSE_WAIT enquanto o processo filho estiver ativo.

Tive um caso em que estava executando o ADB. O próprio ADB gera um processo de servidor se ainda não estiver em execução. Isso herdou todos os meus identificadores inicialmente, mas não apareceu como o proprietário de nenhum deles quando eu estava investigando (o mesmo acontecia com o macOS e o Windows - não tenho certeza sobre o Linux).

Ian
fonte