Frage Wie man einen Sockel in TIME_WAIT gewaltsam schließt?


Ich laufe ein bestimmtes Programm auf Linux, das manchmal abstürzt. Wenn Sie es danach schnell öffnen, hört es auf Socket 49201 statt auf 49200 wie beim ersten Mal. netstat zeigt an, dass 49200 in einem TIME_WAIT-Zustand ist.

Gibt es ein Programm, das Sie ausführen können, um sofort zu erzwingen, dass der Socket aus dem TIME_WAIT-Zustand entfernt wird?


109
2017-09-03 12:57


Ursprung


Wenn Sie hier sind wegen "zu viele TIME_WAIT auf dem Server ", gerade durchgehen die ersten drei Antworten, die die Frage vermeiden, statt sie zu beantworten. - Pacerier


Antworten:


/etc/init.d/networking restart

Lass mich das ausarbeiten. Das Transmission Control Protocol (TCP) ist ein bidirektionales, geordnetes und zuverlässiges Datenübertragungsprotokoll zwischen zwei Endpunkten (Programmen). In diesem Zusammenhang bedeutet der Begriff "zuverlässig", dass die Pakete erneut übertragen werden, wenn sie in der Mitte verloren gehen. TCP garantiert die Zuverlässigkeit durch Zurücksenden von Bestätigungs (ACK) -Paketen für einen einzelnen oder eine Reihe von Paketen, die von dem Peer empfangen werden.

Dies gilt auch für die Steuersignale, wie z. B. die Beendigungsanfrage / -antwort. RFC 793 definiert den TIME-WAIT-Zustand wie folgt:

TIME-WAIT - steht für Warten   genug Zeit, um sicherzugehen       Das Remote-TCP hat die Bestätigung seiner Verbindung empfangen       Beendigungsanfrage.

Siehe das folgende TCP-Zustandsdiagramm: alt text

TCP ist ein bidirektionales Kommunikationsprotokoll. Wenn die Verbindung hergestellt wird, besteht kein Unterschied zwischen dem Client und dem Server. Außerdem kann einer der beiden Benutzer den Anruf beenden, und beide Peers müssen dem Schließen zustimmen, um eine bestehende TCP-Verbindung vollständig zu schließen.

Nennen wir den ersten, der die Quits als den aktiven näher bezeichnet, und den anderen, der passiver näher kommt. Wenn der aktive Verfolger FIN sendet, geht der Zustand zu FIN-WAIT-1. Dann erhält es ein ACK für das gesendete FIN und der Status geht zu FIN-WAIT-2. Sobald er FIN auch vom passiven Schließer erhält, sendet der aktive Schließer das ACK an das FIN und der Status geht an TIME-WAIT. Falls der passive Schließer das ACK nicht an das zweite FIN empfangen hat, wird das FIN-Paket erneut übertragen.

RFC 793 Setzt das TIME-OUT auf das Doppelte der maximalen Segmentlebensdauer oder 2MSL. Da MSL die maximale Zeit, die ein Paket im Internet verbringen kann, auf 2 Minuten festgelegt ist, beträgt 2 MSL 4 Minuten. Da es keinen ACK für einen ACK gibt, kann der aktive Closer nur 4 Minuten warten, wenn er das TCP / IP-Protokoll korrekt hält, nur für den Fall, dass der passive Sender das ACK nicht an sein FIN (theoretisch) erhalten hat. .

In Wirklichkeit sind fehlende Pakete wahrscheinlich selten und sehr selten, wenn alles innerhalb des LANs oder innerhalb eines einzelnen Rechners geschieht.

Um die Frage wörtlich zu beantworten, wie gewaltsam Schließen Sie einen Socket in TIME_WAIT ?, ich bleibe bei meiner ursprünglichen Antwort:

/etc/init.d/networking restart

Praktisch gesprochen würde ich es so programmieren, dass es den TIME-WAIT-Zustand mit der SO_REUSEADDR-Option als WMR ignoriert. Was genau macht SO_REUSEADDR?

Diese Socket-Option teilt dem Kernel mit   dass, selbst wenn dieser Port beschäftigt ist (in
  der TIME_WAIT-Status), gehe voran und   Verwende es trotzdem. Wenn es beschäftigt ist, aber   mit einem anderen Staat wirst du immer noch kommen   ein bereits verwendeter Fehler in der Adresse. Es   ist nützlich, wenn Ihr Server geschlossen wurde   nach unten und dann sofort neu gestartet   während Sockets immer noch aktiv sind   Hafen. Sie sollten sich bewusst sein, dass wenn   es kommen unerwartete Daten rein   verwirren Sie Ihren Server, aber währenddessen   ist möglich, es ist nicht wahrscheinlich.


139
2017-09-03 13:11



Große Antwort, aber nicht die richtige Antwort auf seine Frage. Das Netzwerk neu zu starten würde funktionieren, aber dann würde es neu starten, also kann das nicht stimmen. - Chris Huang-Leaver
@Chris Huang-Leaver, die Frage lautet: "Gibt es ein Programm, das Sie ausführen können, um sofort zu veranlassen, dass der Socket aus dem TIME_WAIT-Zustand entfernt wird?" Wenn das Neustarten als laufendes Programm betrachtet werden könnte, wäre auch dies eine richtige Antwort. Warum denkst du, das kann nicht richtig sein? - Eugene Yokota
WMR hat die nützlichste Antwort (was ich tue, wenn ich auf diese Art von Problem stoße). Neustart des Netzwerks ist zu drastisch, um Lösung zu sein, und könnte länger dauern, als einfach auf das Timeout zu warten. Die richtige Antwort auf seine Frage ist "Nein", aber SO lässt Sie nicht zwei Buchstaben Antworten eingeben :-) - Chris Huang-Leaver
Oh, okay, das nächste Mal, wenn ein Prozess bei SIGTERM hängt, zertrümmere ich meinen Computer, anstatt ihn zu reparieren. - Longpoke


Ich weiß nicht, ob Sie den Quellcode dieses bestimmten Programms haben, aber wenn ja, können Sie SO_REUSEADDR einfach über setzen setsockopt(2) Damit können Sie an der gleichen lokalen Adresse binden, auch wenn der Socket im TIME_WAIT-Zustand ist (es sei denn, dieser Socket hört aktiv zu, siehe socket(7)).

Weitere Informationen zum Status TIME_WAIT finden Sie unter Unix Socket FAQ.


50
2017-09-03 13:17



aber ich habe den bereits gebundenen Fehler nicht bekommen. Wenn ich das Programm erneut ausführe, hört es in post (123456) auch ich kann sehen, dass das System TIME_WAIT für diesen Port zeigt, aber immer noch kann ich verbinden. Warum? - Jayapal Chandran
Auch mit SO_REUSEADDR ist es immer noch möglich, den Fehler "Adresse wird bereits verwendet" zu erhalten. Einzelheiten finden Sie unter hea-www.harvard.edu/~fine/Tech/addrinuse.html. - Jingguo Yao
@ WMR SO_REUSEADDR schließt einen Socket nicht. Es ermöglicht Ihnen lediglich, die bereits geöffneten zu verwenden. Die Frage ist also immer noch "Wie man eine Steckdose gewaltsam schließt TIME_WAIT" - Pacerier


Soweit ich weiß, gibt es keine Möglichkeit, den Socket außerhalb des Schreibens eines besseren Signalhandlers in Ihr Programm zu schließen, aber es gibt eine / proc-Datei, die steuert, wie lange das Timeout dauert. Die Datei ist

/proc/sys/net/ipv4/tcp_tw_recycle

und Sie können das Timeout auf 1 Sekunde setzen, indem Sie Folgendes tun:

echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle 

Jedoch, diese Seite enthält eine Warnung zu möglichen Zuverlässigkeitsproblemen beim Festlegen dieser Variablen.

Es gibt auch eine verwandte Datei

/proc/sys/net/ipv4/tcp_tw_reuse

welches steuert, ob TIME_WAIT Sockets wiederverwendet werden können (vermutlich ohne Zeitüberschreitung).

Übrigens warnt die Kernel-Dokumentation, dass Sie keinen dieser Werte ohne "Beratung / Anfragen von technischen Experten" ändern sollten. Was ich nicht bin.

Das Programm muss geschrieben worden sein, um eine Bindung an Port 49200 zu versuchen und dann um 1 zu erhöhen, wenn der Port bereits verwendet wird. Wenn Sie also die Kontrolle über den Quellcode haben, können Sie dieses Verhalten ändern, um einige Sekunden zu warten und es erneut am selben Port zu versuchen, anstatt zu inkrementieren.


32
2017-09-03 13:24



denke, die zweiten zwei Beispiele sollten s / rw / tw / Ich würde bearbeiten, aber genug rep nicht.
Aus der Kernel-Dokumentation übernommen: Vorsicht. Sowohl tcp_tw_recycle als auch tcp_tw_reuse können Probleme verursachen. Sie sollten auch nicht aktivieren, ohne die Netztopologie zwischen Knoten zu verstehen, die den Knoten verwenden oder verwenden, auf dem der Parameter aktiviert ist. Verbindungen, die über Knoten laufen, die TCP-Verbindungsstatus kennen, wie Firewall, NAT oder Lastenausgleich, können aufgrund der Einstellung Frames löschen. Das Problem wird sichtbar, wenn die Anzahl der Verbindungen groß genug ist.
Einstellen auf 1 funktioniert für zukünftige Verbindungen, aber was ist mit den aktuellen, die bereits geöffnet sind? - Pacerier


Tatsächlich gibt es eine Möglichkeit, eine Verbindung zu töten - killcx. Sie behaupten, es funktioniert in jedem Zustand der Verbindung (die ich nicht überprüft habe). Sie müssen die Schnittstelle kennen, auf der die Kommunikation stattfindet, sie scheint jedoch eth0 als Standard anzunehmen.

UPDATE: Eine andere Lösung ist Cutter Das kommt in einigen Linux Distributionen.


16
2017-10-30 17:32



Vielen Dank! Dieses Dienstprogramm funktioniert großartig! Habe mich davor bewahrt, einen langen Job neu starten zu müssen. - Zanson


Eine andere Option ist die Verwendung der Option SO_LINGER mit einem Timeout von 0. Auf diese Weise wird beim Schließen des Sockets zwangsweise eine RST gesendet, anstatt in das FIN / ACK-Schließverhalten zu wechseln. Dies wird den Zustand TIME_WAIT vermeiden und ist möglicherweise für einige Verwendungszwecke geeigneter.


3
2018-06-10 22:33



Es verliert auch alle ausgehenden Daten, die sich noch im Transit befinden, und kann am anderen Ende einen Fehler verursachen. Nicht empfohlen. - user207421
@EJP Failing früh ist fast immer der richtige Ruf. Vernetzung ist nicht zuverlässig, und das Kämpfen wird die Dinge verlangsamen. Eine abgestürzte App kann nicht davon ausgehen, dass Daten sicher ausgegeben wurden. - Tobu
Eigentlich würde ich das jeden Tag empfehlen, wenn der andere Endpunkt ein fehlerhafter, eingebetteter Industriebus-Gateway ist, der seinen eigenen zuverlässigen Transport auf Anwendungsebene über TCP implementiert, wo der Transport verhindert, dass die Verbindung jemals schließt, wenn sie RST empfängt und daher voll ist das Verbindungslimit für dieses Gateway. Dort. Ich habe Ihnen ein sehr spezifisches und sehr reales Beispiel gegeben, das leider auf solche Hacks zurückgreifen muss. - andyn
@Tobu Networking ist nicht zuverlässig, aber TCP versucht es zu sein, und das Schlimmste zu machen, bedeutet nicht, irgendetwas Besseres zu machen, und TCP seine Arbeit machen zu lassen bedeutet nicht, irgendetwas zu "bekämpfen". - user207421


Eine alternative Lösung wäre eine zuverlässige Proxy- oder Port-Forwarding-Software, die Port 49200 überwacht und dann die Verbindung zu einem von mehreren Instanzen Ihres weniger zuverlässigen Programms mit verschiedenen Ports weiterleitet ... HAPROXY kommt mir in den Sinn.

Übrigens ist der Port, auf dem du ankommst, ziemlich hoch. Sie könnten versuchen, einen unbenutzten knapp über dem 0-1024-Bereich zu verwenden. Es ist weniger wahrscheinlich, dass Ihr System eine niedrigere Portnummer als ephemeren Port verwendet.


2
2017-08-21 20:28





TIME_WAIT ist das häufigste Problem in der Client-Server-Architektur der Socket-Programmierung. Warten Sie ein paar Sekunden, versuchen Sie regelmäßig, die beste Lösung dafür zu finden. Für Echtzeit-Anwendungen müssen sie Server muss sofort aufstehen Es gibt die Option SO_REUSEADDR für sie.


0
2017-10-13 19:07