Manchmal zeigt netstat einen Socket an, der scheinbar feststeckt. Die entfernte Anwendung wurde beendet, manchmal wurde sogar die OpenVOS-Anwendung beendet, aber netstat zeigt den Socket immer noch an. In diesem Artikel wird erklärt, warum das passiert und was Sie dagegen tun können.
Eine kurze Einführung in die TCP-Zustände
Wenn Sie "tcp-Statusdiagramm" googeln, finden Sie eine Fülle von Bildern, von denen einige kaum lesbar und andere recht gut lesbar sind. Wikimedia hat ein sehr schönes farbkodiertes Diagramm (http://commons.wikimedia.org/wiki/File:TCP_state_diagram.png). Der TCP RFC (793) (http://www.rfc-editor.org/rfc/rfc793.txt) hat ein ASCII-Diagramm und erklärt natürlich die Zustände im Detail.
Sockets können steckenbleiben, wenn sie darauf warten, dass entweder die lokale Anwendung oder der entfernte Host etwas tut. Es gibt drei Zustände, in denen dies geschieht. Im Zustand FIN_WAIT_2 wartet der Socket darauf, dass der entfernte Host die Verbindung schließt. Im Zustand CLOSE_WAIT wartet er darauf, dass die lokale Anwendung den Socket schließt, und im Zustand ESTABLISHED wartet er darauf, dass der entfernte Host sein Sendefenster öffnet, oder dass die lokale Anwendung etwas sendet. Wenn der lokale TCP-Stack Daten gesendet hat und auf die Bestätigung des entfernten Hosts wartet, kann er nicht stecken bleiben, sondern wird schließlich einen Timeout erleiden, der lokalen Anwendung einen Fehler melden und den Socket schließen.
FIN_WAIT_2 Zustand
Dies ist vielleicht der häufigste Fall eines steckengebliebenen Sockets, der an das CAC herangetragen wird. Die lokale Anwendung hat den Socket geschlossen und kann beendet worden sein. Der typische Grund dafür, dass Sockets in diesem Zustand stecken bleiben, ist, dass die entfernte Anwendung aufgehängt ist und ihren Socket nicht liest.
Wenn der STCP-Parameter finwait2 auf einen Wert von N > 0 gesetzt wird, werden Sockets geschlossen, nachdem sie sich N Sekunden lang im FIN_WAIT_2 befunden haben. Ab den Versionen 14.7.2bg, 14.7.tl1, 15.2.1aa, 15.2.tel.af, 15.3.0bd, 15.3.tel.ag, 16.2.1al, 17.0.0ai und 17.1 ist der Standardwert 1200, davor war der Standardwert 0 (wenn Sie also möchten, dass die Sockets ein Timeout haben, müssen Sie den Wert selbst einstellen). Sie können den aktuellen Wert mit der list_stcp_params analyze_system Anfrage sehen, Sie können den Wert mit der set_stcp_param analyze_system Anfrage ändern. Die Dokumentation zu diesen Abfragen finden Sie im OpenVOS-Handbuch zur Systemanalyse (R073), das unter http://stratadoc.stratus.com verfügbar ist.
Zustand CLOSE_WAIT
Dies ist der nächsthäufigere Zustand eines festsitzenden Sockets. Sockets im Zustand CLOSE_WAIT warten darauf, dass die lokale Anwendung den Socket schließt. Der typische Grund dafür, dass ein Socket in diesem Zustand bleibt, ist, dass die Anwendung den Socket nicht mehr liest. Der einfachste Weg, den Socket zu schließen, ist, die lokale Anwendung zu beenden.
Wenn das Beenden der lokalen Anwendung keine Option ist, können Sie nur ein Paket mit gesetztem RST-Flag (Reset) erstellen. Dazu müssen Sie die vom Socket verwendeten Sequenznummern kennen (verfügbar mit der Abfrage dump_onetcb analyze_system) und ein Dienstprogramm auf einem anderen Host im lokalen Subnetz haben, das benutzerdefinierte IP-Pakete erstellen und senden kann. Diese Dienstprogramme sind für Windows- und Linux-Systeme verfügbar.
Eingerichteter Zustand
Da netstat die meiste Zeit Sockets im ESTABLISHED-Zustand anzeigt, wie können Sie feststellen, wann der Socket feststeckt? Wenn Sie eine Meldung erhalten, dass der entfernte Host abgestürzt ist oder das Netzwerk zwischen dem lokalen und dem entfernten Host mehr als 10 Minuten lang ausgefallen ist und die lokale Anwendung darauf wartet, dass der entfernte Host ihr etwas sendet, können Sie ziemlich sicher sein, dass der Socket feststeckt. In diesem Fall wird der von netstat gemeldete Wert der Sendewarteschlange (die Zahl unmittelbar links von der lokalen IP-Adresse) 0 sein. Ist der Wert der Sendewarteschlange hingegen größer als 0 und bleibt er bestehen, kann es sein, dass der entfernte Host ein Null-Fenster anzeigt.
Im ersten Fall bleibt der Socket im ESTABLISHED-Zustand, bis die lokale Anwendung beendet wird, es sei denn, keep-alive ist eingeschaltet. Wenn keep-alive eingeschaltet ist, sendet STCP nach Ablauf des keep-alive-Timers einen keep-alive-Test. Bleibt die Probe unbeantwortet, wird sie erneut gesendet, aber nach einigen Minuten und mehreren erneuten Übertragungen wird die Verbindung beendet. Standardmäßig ist die Schnittstelle auf keep-alive eingestellt, aber auch die Sockets sind standardmäßig nicht auf keep-alive eingestellt. Um keep-alive auf einem Socket zu setzen, muss die Anwendung den Funktionsaufruf setsockopt verwenden. Einzelheiten finden Sie im OpenVOS STREAMS TCP/IP Programming (R420) Handbuch, das auch unter http://stratadoc.stratus.com verfügbar ist. Die voreingestellte Keep-Alive-Zeit beträgt 2 Stunden; das bedeutet, dass die erste Keep-Alive-Sonde 2 Stunden nach dem Empfang des letzten TCP-Segments vom entfernten Host gesendet wird. Wer nicht so geduldig ist, kann die Keep-alive-Zeit sowie die Zeit zwischen den Sonden und die Anzahl der Sonden mit der Abfrage set_stcp_parameter in analyze_system einstellen. Ich empfehle nicht, diese Parameter ohne eine detaillierte Analyse zu ändern.
Wenn für den Socket kein keep-alive gesetzt ist, besteht die einzige einfache Möglichkeit darin, die Anwendung, die den Socket besitzt, zu beenden. Wenn dies nicht möglich ist, kann der Socket geschlossen werden, indem ein Segment mit gesetztem RST-Flag gesendet wird.
Um den zweiten Fall zu bestätigen, prüfen Sie den Wert von sndws, der von der Abfrage dump_onetcb analyze_system angezeigt wird. Ein Wert von 0 bedeutet ein geschlossenes Fenster. Sie können auch packet_monitor ausführen, um die Verbindung zu verfolgen und den Fensterwert im TCP-Header in Segmenten vom entfernten Host zu überprüfen. Ein Wert von "n.a." bedeutet 0.
Ich möchte betonen, dass dies ein behebbarer Zustand sein kann. Manchmal verzögern sich Anwendungen, und der TCP-Stack schließt das Fenster; wenn die Anwendung den Rückstand aufgeholt hat, öffnet der Stack das Fenster wieder. In den meisten Fällen kann man jedoch davon ausgehen, dass die Anwendung, wenn sie sich nach ein paar Minuten noch nicht erholt hat, es auch nicht tun wird. Eine Ausnahme könnte z. B. ein Drucker sein, der kein Papier mehr hat. Ein Socket in diesem Zustand kann in diesem Zustand bleiben, auch wenn die VOS-Anwendung, die ihn erzeugt hat, beendet wird.
Diese Sockets können bereinigt werden, indem tcp_zerowin_abort_interval$ auf einen Wert von N > 0 gesetzt wird. Die Sockets werden N Sekunden nach dem Empfang des nächsten TCP-Segments mit einem Null-Fenster bereinigt. Window Probes werden alle 100 Sekunden gesendet, um zu bestätigen, dass das Empfangsfenster des entfernten Hosts noch geschlossen ist, so dass im schlimmsten Fall innerhalb von 100 Sekunden eine Antwort empfangen wird. Der Standardwert von tcp_zerowin_abort_interval$ ist Null und ich schlage vor, ihn auf 0 zu belassen, es sei denn, Sie müssen einen Socket aufräumen. In diesem Fall schlage ich vor, den Wert auf einen kleinen Wert zu setzen, z.B. 10 Sekunden, und ihn nach dem Bereinigen des Sockets wieder auf 0 zu setzen. Ich denke, dies verringert das Risiko, Sockets zu löschen, die wiederherstellbar sind.
Um diesen Wert zu setzen, müssen Sie die set_longword-Abfrage in analyze_system verwenden. Denken Sie daran, dass N in Hexadezimal angegeben wird. Um den Wert zum Beispiel auf 10 zu setzen, würde die Abfrage lauten:
set_longword tcp_zerowin_abort_interval$ a