Ich führe ein bestimmtes Programm unter Linux aus, das manchmal abstürzt. Wenn Sie es danach schnell öffnen, hört es den Socket 49201 anstelle von 49200 wie beim ersten Mal ab. netstat gibt an, dass sich 49200 in einem TIME_WAIT-Status befindet.
Gibt es ein Programm, das Sie ausführen können, um sofort zu erzwingen, dass der Socket aus dem TIME_WAIT-Status verschoben wird?
TIME_WAIT
Servern" hier sind , überspringen Sie einfach die ersten drei Antworten, um die Frage zu vermeiden, anstatt sie zu beantworten.Antworten:
Lassen Sie mich näher darauf eingehen. Das Transmission Control Protocol (TCP) ist als bidirektionales, geordnetes und zuverlässiges Datenübertragungsprotokoll zwischen zwei Endpunkten (Programmen) konzipiert. 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 das Zurücksenden von Bestätigungspaketen (Acknowledgement, ACK) für ein einzelnes Paket oder einen Bereich von Paketen, die vom Peer empfangen wurden.
Dies gilt auch für die Steuersignale wie Beendigungsanforderung / -antwort. RFC 793 definiert den Status TIME-WAIT wie folgt:
Siehe folgendes TCP-Zustandsdiagramm:
TCP ist ein bidirektionales Kommunikationsprotokoll. Wenn die Verbindung hergestellt wird, gibt es keinen Unterschied zwischen dem Client und dem Server. Beide können auch Quits aufrufen, und beide Peers müssen sich auf das Schließen einigen, um eine hergestellte TCP-Verbindung vollständig zu schließen.
Nennen wir den ersten, der die Quits als aktiven Näher bezeichnet, und den anderen, der den passiven Näher bezeichnet. Wenn der aktive Schließer FIN sendet, geht der Status zu FIN-WAIT-1. Dann erhält es eine ACK für das gesendete FIN und der Zustand geht zu FIN-WAIT-2. Sobald er FIN auch vom passiven Schließer empfängt, sendet der aktive Schließer die ACK an den FIN und der Zustand geht zu TIME-WAIT. Falls der passive Schließer die ACK für die zweite FIN nicht erhalten hat, überträgt er das FIN-Paket erneut.
RFC 793 legt das TIME-OUT auf das Doppelte der maximalen Segmentlebensdauer oder 2MSL fest. Da MSL, die maximale Zeit, die ein Paket im Internet durchwandern kann, auf 2 Minuten festgelegt ist, beträgt 2MSL 4 Minuten. Da es keine ACK für eine ACK gibt, kann der aktive Schließer nichts anderes tun, als 4 Minuten zu warten, wenn er das TCP / IP-Protokoll korrekt einhält, nur für den Fall, dass der passive Absender die ACK für seine FIN nicht erhalten hat (theoretisch) .
In der Realität sind fehlende Pakete wahrscheinlich selten und sehr selten, wenn alles im LAN oder auf einer einzelnen Maschine stattfindet.
Um die Frage wörtlich zu beantworten, wie ein Socket in TIME_WAIT gewaltsam geschlossen wird, halte ich mich weiterhin an meine ursprüngliche Antwort:
In der Praxis würde ich es so programmieren, dass es den TIME-WAIT-Status mit der SO_REUSEADDR-Option ignoriert, wie in WMR erwähnt. Was genau macht SO_REUSEADDR?
quelle
/etc/init.d/networking
ist plattformspezifisch (Debian?), So dass sich die genaue Befehlszeile für andere Systeme (manchmal radikal) unterscheidet. Ich stimme anderen Kommentatoren zu, dass dies ein schwerer Overkill und offensichtlich störend für alle nicht verwandten Netzwerkdienste zu sein scheint.Ich weiß nicht, ob Sie den Quellcode des bestimmten Programms haben, das Sie ausführen, aber wenn ja, können Sie SO_REUSEADDR festlegen, über
setsockopt(2)
das Sie dieselbe lokale Adresse binden können, auch wenn sich der Socket im Status TIME_WAIT befindet (sofern dies nicht der Fall ist) Buchse hört aktiv zu, siehesocket(7)
).Weitere Informationen zum Status TIME_WAIT finden Sie in den häufig gestellten Fragen zum Unix-Socket .
quelle
SO_REUSEADDR
"schließt" keinen Socket. Sie können nur die bereits geöffneten wiederverwenden. Die Frage ist also immer noch: "Wie kann man eine Steckdose zwangsweise schließenTIME_WAIT
?"SO_REUSEADDR
werdebind()
weitermachen lassen ; aber wenn du dann auf diese buchse hören willst, kehre egallisten()
zurückEADDRINUSE
. Mit anderen Worten, diese Antwort hilft möglicherweise Client-Software bei der Verwendung von kurzlebigen Ports, löst jedoch nicht das Problem für Server-Software.Soweit ich weiß, gibt es keine Möglichkeit, den Socket außerhalb des Schreibens eines besseren Signal-Handlers in Ihr Programm zwangsweise zu schließen, aber es gibt eine / proc-Datei, die steuert, wie lange das Timeout dauert. Die Datei ist
und Sie können das Timeout auf 1 Sekunde einstellen, indem Sie dies tun:
Diese Seite enthält jedoch eine Warnung zu möglichen Zuverlässigkeitsproblemen beim Festlegen dieser Variablen.
Es gibt auch eine zugehörige Datei
Hiermit wird gesteuert, ob TIME_WAIT-Sockets wiederverwendet werden können (vermutlich ohne Timeout).
Im Übrigen warnt Sie die Kerneldokumentation davor, einen dieser Werte ohne "Ratschläge / Anfragen von technischen Experten" zu ändern. 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 so ändern, dass Sie einige Sekunden warten und es am gleichen Port erneut versuchen, anstatt ihn zu erhöhen.
quelle
1
für zukünftige Verbindungen funktioniert, aber was ist mit den aktuellen Verbindungen, die bereits geöffnet sind?Tatsächlich gibt es eine Möglichkeit, eine Verbindung zu beenden - killcx . Sie behaupten, es funktioniert in jedem Zustand der Verbindung (die ich nicht überprüft habe). Sie müssen jedoch die Schnittstelle kennen, an der die Kommunikation stattfindet. Sie scheint standardmäßig eth0 anzunehmen.
UPDATE: Eine andere Lösung ist Cutter, die in den Repositories einiger Linux-Distributionen enthalten ist.
quelle
Eine andere Option ist die Verwendung der Option SO_LINGER mit einer Zeitüberschreitung von 0. Auf diese Weise wird beim Schließen des Sockets ein RST gesendet, anstatt das FIN / ACK-Schließverhalten zu aktivieren. Dies vermeidet den TIME_WAIT-Status und ist möglicherweise für einige Verwendungszwecke besser geeignet.
quelle
Eine alternative Lösung wäre, eine zuverlässige Proxy- oder Portweiterleitungssoftware zu haben, die Port 49200 abhört und dann die Verbindung über verschiedene Ports an eine von mehreren Instanzen Ihres weniger zuverlässigen Programms weiterleitet ... HAPROXY ist eine gute Idee.
Übrigens ist der Port, an dem Sie eine Verbindung herstellen, ziemlich hoch. Sie können versuchen, einen nicht verwendeten Wert direkt über dem Bereich 0-1024 zu verwenden. Es ist weniger wahrscheinlich, dass Ihr System eine niedrigere Portnummer als kurzlebigen Port verwendet.
quelle
TIME_WAIT ist das häufigste Problem bei der Socket-Programmierung der Client-Server-Architektur. Warten Sie einige Sekunden und versuchen Sie es in regelmäßigen Abständen. Für Echtzeitanwendungen, die der Server benötigt, muss er sofort aufstehen. Für sie gibt es die Option SO_REUSEADDR.
quelle