Il server socket TCP accumula CLOSE_WAIT occasionalmente nel tempo finché non diventa inutilizzabile

StackOverflow https://stackoverflow.com/questions/679643

Domanda

Speriamo che qualcuno possa aiutarci visto che stiamo arrivando al limite delle indagini!

Abbiamo un semplice server socket asincrono scritto in C# che accetta connessioni da un'applicazione Web ASP.NET, riceve un messaggio, esegue alcune elaborazioni (di solito contro un DB ma anche altri sistemi) e quindi invia una risposta al client .Il client è responsabile della chiusura della connessione.

Abbiamo riscontrato problemi per cui, se il sistema è sotto carico pesante per un lungo periodo di tempo (solitamente giorni), i socket CLOSE_WAIT si accumulano sul server box (netstat -a) al punto che il processo non accetta ulteriori connessioni .A quel punto dobbiamo far rimbalzare il processo e farlo ripartire.

Abbiamo provato a eseguire alcuni test di carico della nostra applicazione ASP.NET per tentare di replicare il problema (perché non era possibile dedurre alcuni problemi dal codice).Pensiamo di esserci riusciti e ci siamo ritrovati con un WireShark traccia del pacchetto del problema che si manifesta come SocketException nei log del server socket:

System.Net.Sockets.SocketException:Una connessione esistente è stata forzatamente chiusa dall'host remoto su system.net.sockets.socket.beginsend (buffer byte [], offset int32, dimensione int32, socketflags Socketflags, callback AsyncCallback, stato di oggetto)

Ho provato a riprodurre il problema dalla traccia del pacchetto come un processo a thread singolo che comunica direttamente con il server socket (utilizzando lo stesso codice dell'app ASP.NET) e non sono riuscito.

Qualcuno ha qualche suggerimento sulle prossime cose da provare, verificare o cose ovvie che potremmo fare in modo sbagliato?

È stato utile?

Soluzione

Guarda lo schema

http://en.wikipedia.org/wiki/File:Tcp_state_diagram_fixed.svg

Il suo cliente ha chiuso la connessione chiamando close (), che ha inviato FIN al socket server, che ACKed la FIN e lo Stato di cui ora è cambiato a CLOSE_WAIT, e rimane in questo modo a meno che il problemi di server close () invocano che presa.

Il programma server ha bisogno di rilevare se il cliente ha interrotto la connessione, e quindi chiudere () immediatamente per liberare la porta. Come? Fare riferimento a read (). Dopo aver letto end-of-file (FIN significa ricevuto), viene restituito zero.

Altri suggerimenti

Se il tuo server si sta accumulando CLOSE_WAIT socket, non chiuderà il socket una volta completata la connessione.Se dai un'occhiata al diagramma di stato nel commento al post di Chris, lo vedrai CLOSE_WAIT transizioni a LAST_ACK una volta chiusa la presa e il FIN è stato inviato.

Dici che è complesso determinare dove farlo a causa della natura asincrona?Questo non dovrebbe essere un problema, dovresti chiudere il socket se la richiamata dal tuo recv restituisce 0 byte (supponendo che tu non abbia nient'altro da fare una volta che il tuo client chiude il suo lato della connessione).Se devi preoccuparti di continuare a inviare, esegui uno Shutdown (recv) qui e prendi nota che il tuo client ha chiuso, una volta terminato l'invio, esegui uno Shutdown (send) e una chiusura.

POTRESTI emettere una nuova lettura nella richiamata dalla lettura che restituisce 0 indicando che il client è stato chiuso e questo potrebbe causare problemi?

  

Il cliente ha il compito di chiudere la connessione.

Sia il client e il server deve chiudere e spegnimento il socket. Sia il client non sta finendo la stretta (improbabile - in quanto avrebbe dovuto È gestito finalizzatore) o il server non è in fase di arresto della presa (probabile)

.
using (Socket s = new Socket(/* */)) {
  /* Do stuff */
  s.Shutdown(SocketShutdown.Both);
  s.Close();
}

Non si dovrebbe essere lasciando la responsabilità di chiudere i socket TCP solo fino al cliente. Cosa succede se il processo client / macchina si blocca?

Idealmente si dovrebbe avere un timeout in atto in modo che, se non il traffico viene ricevuto su un socket connesso dopo un certo periodo di tempo poi viene chiusa dal server.

Non importa cosa succede quando tutte le operazioni dello zoccolo ha terminato da parte del cliente, e non ha bisogno di fare qualsiasi operazione di lettura più sul socket, il cliente deve emettere un comando di chiusura.

Questa emissione di comando di chiusura, dice semplicemente l'ascoltatore (il server) che la connessione deve essere chiuso.

In parole semplici, quando il server emette di nuovo un comando di lettura (listener.read () o listener.beginread (...) in modalità asincrona), la lettura tornerà a 0 bytes leggere, questo di per sé indica che il zoccolo deve essere chiuso dall'ascoltatore come altre operazioni sul portalampada è cessata dal cliente.

CLOSE_WAIT del sono destinate ad appendere circa per un tempo dopo un socket viene chiusa, per impedire riutilizzare lo stesso numero di socket e ricevendo pacchetti dalla vecchia connessione. Questo vi darà solo te Il dolore se si sta aprendo e chiudendo una serie di prese huuuuge molto velocemente.

Modifica -. Dovrebbe essere TIME_WAIT, non CLOSE_WAIT sopra

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top