Wie entferne ich eine CLOSE_WAIT-Socket-Verbindung?

88

Ich habe ein kleines Programm geschrieben, das mit einem Server an einem bestimmten Port interagiert. Das Programm funktioniert gut, aber:

Sobald das Programm unerwartet beendet wurde und seitdem diese Socket-Verbindung im CLOSE_WAITStatus angezeigt wird . Wenn ich versuche, ein Programm auszuführen, bleibt es hängen und ich muss es schließen, wodurch sich noch mehr CLOSE_WAIT Socket-Verbindungen ansammeln .

Gibt es eine Möglichkeit, diese Verbindungen zu spülen?

Dilletante
quelle
4
Sie können (und sollten) nicht. CLOSE_WAIT ist ein von TCP definierter Status für Verbindungen, die geschlossen werden und darauf warten, dass das Gegenstück dies bestätigt.
vonbrand
1
Siehe auch unix.stackexchange.com/questions/10106/… ..., über das ich nicht als Duplikat abstimmen werde, da die Frage dann als nicht zum Thema gehörend geschlossen würde.
Derobert
3
@vonbrand Nein, ist es nicht, es ist genau das Gegenteil. Dies ist der Status für eine Verbindung, die bereits vom Peer geschlossen wurde und darauf wartet, dass die lokale Anwendung ihr Ende schließt.
Marquis von Lorne
Wenn Sie Commons HttpClient verwenden, enthält nuxeo.com/blog/… viele relevante Informationen. Ab RFC 2616, Abschnitt 14: HTTP / 1.1-Anwendungen, die keine dauerhaften Verbindungen unterstützen, MÜSSEN in jeder Nachricht die Verbindungsoption "Schließen" enthalten sein.
Mayank Ahuja

Antworten:

75

CLOSE_WAITbedeutet, dass Ihr Programm noch ausgeführt wird und den Socket nicht geschlossen hat (und der Kernel darauf wartet). Fügen Sie hinzu -p, netstatum die PID zu erhalten, und töten Sie sie dann stärker (bei SIGKILLBedarf mit). Das sollte deine CLOSE_WAITSteckdosen loswerden . Sie können auch verwenden ps, um die PID zu finden.

SO_REUSEADDRist für Server und TIME_WAITSockets, gilt also hier nicht.

derobert
quelle
2
Nun ... das Kiling des Prozesses ist möglicherweise nicht das Beste, wenn dieses Programm viele Verbindungen aufbaut, nur einige von denen, die in "CLOSE_WAIT" bleiben. In diesem Fall kann das Beenden des Prozesses völlig unmöglich oder unangemessen sein (das Programm funktioniert immer noch und bietet Dienste mit diesen anderen Verbindungen an). Nur die ausstehende Verbindung zu schließen, wäre viel angemessener. In der Tat ist es normalerweise das Programm selbst, das das Connectino nicht lokal schließt (CLOSE_WAIT bedeutet, dass es vom anderen Ende 'FIN' empfangen hat und das Programm die Verbindung nur lokal schließen muss). Ein Fehlerbericht kann angebracht sein
Olivier Dulac
40

Wie von Crist Clark beschrieben .

CLOSE_WAIT bedeutet, dass das lokale Ende der Verbindung vom anderen Ende eine FIN erhalten hat, das Betriebssystem jedoch darauf wartet, dass das Programm am lokalen Ende seine Verbindung tatsächlich schließt.

Das Problem ist, dass Ihr Programm, das auf dem lokalen Computer ausgeführt wird, den Socket nicht schließt. Es handelt sich nicht um ein TCP-Optimierungsproblem. Eine Verbindung kann (und zu Recht) für immer in CLOSE_WAIT bleiben, während das Programm die Verbindung offen hält.

Sobald das lokale Programm den Socket schließt, kann das Betriebssystem die FIN an das Remote-Ende senden, das Sie zu LAST_ACK überführt, während Sie auf die Bestätigung der FIN warten. Sobald dies empfangen wurde, ist die Verbindung beendet und wird aus der Verbindungstabelle entfernt (wenn sich Ihr Ende in CLOSE_WAIT befindet, befinden Sie sich nicht im Status TIME_WAIT).

user2618402
quelle
4
Wie schließe ich die Steckdose?
Divyang Shah
1
Sie schließen den Griff an der Steckdose, die Sie geöffnet haben. Verwenden Sie close()oder closesocket(), je nachdem, welche Plattform Sie verwenden.
Remy Lebeau
8

Ich habe auch das gleiche Problem mit einem neuesten Tomcat-Server (7.0.40). Es reagiert einmal für ein paar Tage nicht mehr.

Um offene Verbindungen anzuzeigen, können Sie Folgendes verwenden:

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

Wie in diesem Beitrag erwähnt , können Sie /proc/sys/net/ipv4/tcp_keepalive_timedie Werte anzeigen. Der Wert scheint in Sekunden zu sein und ist standardmäßig 7200 (dh 2 Stunden).

Um sie zu ändern, müssen Sie bearbeiten /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
quelle
4
Die Antwort ist verwirrend. Sie sagten, die nicht reagierenden Zustände seien seit mehreren Tagen verschwunden. Dann versuchen Sie aber auch, die Keep-Alive-Zeit auf nur 120 Sekunden einzustellen. Selbst mit dem Standardwert (7200 Sek.) sollte es nicht mehrere Tage dauern, oder?
Fanchyna
8

Auch wenn zu viele CLOSE_WAIT-Verbindungen bedeuten, dass im ersten Code etwas mit Ihrem Code nicht stimmt, wird dies als nicht bewährte Methode akzeptiert.

Vielleicht möchten Sie Folgendes überprüfen: https://github.com/rghose/kill-close-wait-connections

Dieses Skript sendet die ACK, auf die die Verbindung gewartet hat.

Das hat bei mir funktioniert.

Fata Morgana
quelle
Sie senden Act an Close-Wait-Socket. mit funktioniert nicht .. wenn funktioniert, warum?
Chinaxing
Ich vermute, das Betriebssystem hat die FIN bereits an den Remote-Host gesendet. Der Remote-Host kann wahrscheinlich nicht mit der vom Socket erwarteten ACK antworten.
Mirage
Ja, das stimmt (aus dem Kernel-Code). Ich bezweifle aber auch die SEQ des von Ihnen gesendeten Pakets, nämlich "10". Überprüft der Kernel dies nicht?
Chinaxing
Wahrscheinlich nicht. Ich glaube, ich habe es mit vielen Zufallszahlen versucht, und sie schienen zu funktionieren.
Mirage
3

Es sollte erwähnt werden, dass die SocketInstanz sowohl im Client- als auch im Serverende explizit aufgerufen werden muss close(). Wenn dann auch nur eines der Enden close()aufgerufen wird, bleibt der Socket im Status CLOSE_WAIT.

Binita Bharati
quelle
2

Sie können Sockets mit ssBefehl zwangsweise schließen . Der ssBefehl ist ein Tool zum Speichern von Socket-Statistiken und zeigt Informationen auf ähnliche Weise (obwohl einfacher und schneller) wie netstat an.

Führen Sie dies aus (als root), um einen Socket im Status CLOSE_WAIT zu beenden.

$ ss --tcp state CLOSE-WAIT --kill
Mustapha Hadid
quelle
1

Es ist auch erwähnenswert, dass, wenn Ihr Programm einen neuen Prozess erzeugt, dieser Prozess möglicherweise alle geöffneten Handles erbt. Selbst nach Ihrem eigenen Programmabschluss können diese geerbten Handles über den verwaisten untergeordneten Prozess noch aktiv sein. Und sie zeigen sich in netstat nicht unbedingt gleich. Trotzdem bleibt der Socket in CLOSE_WAIT hängen, während dieser untergeordnete Prozess aktiv ist.

Ich hatte einen Fall, in dem ich ADB ausführte. ADB selbst erzeugt einen Serverprozess, falls dieser noch nicht ausgeführt wird. Dies erbte anfangs alle meine Handles, zeigte sich jedoch bei meiner Untersuchung nicht als Eigentümer eines dieser Handles (das gleiche galt sowohl für MacOS als auch für Windows - ich bin mir bei Linux nicht sicher).

Ian
quelle