Come si rimuove una connessione socket CLOSE_WAIT


91

Ho scritto un piccolo programma che interagisce con un server su una porta specifica. Il programma funziona bene, ma:

Una volta che il programma è terminato in modo imprevisto, e da allora la connessione socket viene mostrata nello CLOSE_WAITstato. Se provo a eseguire un programma si blocca e devo forzare la chiusura, il che accumula ancora più CLOSE_WAIT connessioni socket.

C'è un modo per svuotare queste connessioni?


4
Non puoi (e non dovresti). CLOSE_WAIT è uno stato definito da TCP per le connessioni chiuse in attesa che la controparte lo riconosca.
vonbrand

1
Vedi anche unix.stackexchange.com/questions/10106/… ... che non voterò come duplicato, perché finirebbe per chiudere la domanda come fuori tema.
derobert

3
@vonbrand No non lo è, è esattamente l'opposto. È lo stato di una connessione che è già stata chiusa dal peer e attende che l'applicazione locale chiuda la sua fine.
Marchese di Lorne

Se stai usando Commons HttpClient, nuxeo.com/blog/… contiene molte informazioni rilevanti. Da RFC 2616, Sezione 14: le applicazioni HTTP / 1.1 che non supportano le connessioni persistenti DEVONO includere l'opzione di "chiusura" della connessione in ogni messaggio.
Mayank Ahuja

Risposte:


79

CLOSE_WAITsignifica che il tuo programma è ancora in esecuzione e non ha chiuso il socket (e il kernel sta aspettando che lo faccia). Aggiungi -pa netstatper ottenere il pid, quindi uccidilo con più forza (con SIGKILLse necessario). Questo dovrebbe sbarazzarti delle tue CLOSE_WAITprese. Puoi anche usare psper trovare il pid.

SO_REUSEADDRè per server e TIME_WAITsocket, quindi non si applica qui.


2
beh ... uccidere il processo potrebbe non essere il massimo se quel programma apre molte connessioni, solo pochi di quelli rimangono in "CLOSE_WAIT": in tal caso uccidere il processo potrebbe essere completamente impossibile o inappropriato (il programma funziona ancora e fornisce servizi, con quelle altre connessioni). La semplice chiusura della connessione in sospeso sarebbe molto più appropriata. ma in effetti di solito è il programma stesso che non chiude localmente il connectino (CLOSE_WAIT significa che ha ricevuto 'FIN' dall'altra parte e il programma deve solo chiudere la connessione localmente). Una segnalazione di bug potrebbe essere appropriata
Olivier Dulac

40

Come descritto da Crist Clark .

CLOSE_WAIT significa che l'estremità locale della connessione ha ricevuto un FIN dall'altra estremità, ma il sistema operativo sta aspettando che il programma all'estremità locale chiuda effettivamente la sua connessione.

Il problema è che il tuo programma in esecuzione sulla macchina locale non chiude il socket. Non è un problema di ottimizzazione TCP. Una connessione può (e abbastanza correttamente) rimanere in CLOSE_WAIT per sempre mentre il programma mantiene la connessione aperta.

Una volta che il programma locale chiude il socket, il sistema operativo può inviare il FIN all'estremità remota che ti fa passare a LAST_ACK mentre aspetti l'ACK del FIN. Una volta che si riceve, la connessione è finito e scende dalla tabella dei collegamenti (se il finale è in CLOSE_WAIT tu non finire in stato TIME_WAIT).


4
come chiudere la presa ??
Divyang Shah

1
Chiudi la maniglia che hai alla presa che hai aperto. Usa close()o closesocket(), a seconda della piattaforma che stai utilizzando.
Remy Lebeau

8

Sto riscontrando lo stesso problema anche con un server Tomcat molto recente (7.0.40). Non risponde una volta per un paio di giorni.

Per vedere le connessioni aperte, puoi usare:

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

Come accennato in questo post , puoi utilizzare /proc/sys/net/ipv4/tcp_keepalive_timeper visualizzare i valori. Il valore sembra essere in secondi e il valore predefinito è 7200 (cioè 2 ore).

Per cambiarli, devi modificare /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`

4
la risposta è confusa. hai detto che gli stati di non risposta sono passati per diversi giorni .. ma poi provi anche a impostare il tempo di mantenimento in vita a soli 120 secondi. anche con il valore predefinito (7200 sec), non dovrebbe durare diversi giorni, giusto?
fanchyna

8

Anche se un numero eccessivo di connessioni CLOSE_WAIT significa che c'è qualcosa di sbagliato nel tuo codice nel primo e questo è accettato non è una buona pratica.

Potresti voler controllare: https://github.com/rghose/kill-close-wait-connections

Quello che fa questo script è inviare l'ACK che la connessione stava aspettando.

Questo è ciò che ha funzionato per me.


si invia act al socket close-wait. con non funziona .. se funziona, perché?
Chinaxing

Immagino che il sistema operativo abbia già inviato la FIN all'host remoto. L'host remoto probabilmente non può rispondere con l'ACK che il socket si aspetta.
miraggio

sì, è vero (dal codice del kernel). ma dubito anche del SEQ del pacchetto che mandi, che è "10", il kernel non lo controlla?
Chinaxing

Probabilmente no. Penso di aver provato con molti numeri casuali e sembravano funzionare.
miraggio

3

Va ricordato che l' Socketistanza sia sul client che sul server deve essere invocata esplicitamente close(). Se solo una delle estremità invoca close()anche allora, il socket rimarrà nello stato CLOSE_WAIT.


3

Puoi chiudere forzatamente i socket con il sscomando; il sscomando è uno strumento utilizzato per scaricare le statistiche sui socket e visualizza le informazioni in modo simile (sebbene più semplice e veloce) a netstat.

Per uccidere qualsiasi socket nello stato CLOSE_WAIT, eseguilo (come root)

$ ss --tcp state CLOSE-WAIT --kill

1

Vale anche la pena notare che se il tuo programma genera un nuovo processo, quel processo potrebbe ereditare tutti gli handle aperti. Anche dopo il blocco del programma, gli handle ereditati possono essere ancora attivi tramite il processo del bambino orfano. E non si presentano necessariamente allo stesso modo in netstat. Tuttavia, il socket rimarrà in sospeso in CLOSE_WAIT mentre questo processo figlio è attivo.

Ho avuto un caso in cui gestivo ADB. Lo stesso ADB genera un processo del server se non è già in esecuzione. Questo ha ereditato inizialmente tutti i miei handle, ma non si è rivelato il proprietario di nessuno di essi quando stavo indagando (lo stesso valeva sia per macOS che per Windows - non sono sicuro di Linux).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.