TCP-Option SO_LINGER (Null) - wenn es erforderlich
-
04-10-2019 - |
Frage
Ich denke, dass ich die formale Bedeutung der Option verstehen. In einigen Legacy-Code jetzt bin ich der Handhabung, wird die Option verwendet. Der Kunde beschwert sich über RST als Antwort auf FIN von seiner Seite auf der Verbindung nahe von seiner Seite.
Ich bin nicht sicher, kann ich es sicher entfernen, da verstehe ich nicht, wenn es verwendet werden soll.
Können Sie bitte ein Beispiel geben, wenn die Option erforderlich wäre?
Lösung
Der typische Grund für eine SO_LINGER
Timeout von Null zu setzen, ist ein große Anzahl von Verbindungen zu vermeiden, in dem TIME_WAIT
Zustand sitzen, alle auf einem Server zur Verfügung stehenden Ressourcen zu binden.
Wenn eine TCP-Verbindung sauber geschlossen ist, das Ende, das die engen eingeleitet ( „active close“) endet mit der Verbindung in TIME_WAIT
für einige Minuten sitzen. Also, wenn Ihr Protokoll ist ein, wo die Server initiiert die Verbindung zu schließen, und eine sehr große Anzahl von kurzlebigen Verbindungen beinhalten, dann könnte es für dieses Problem anfällig sein.
Das ist keine gute Idee, wenn auch - TIME_WAIT
aus einem Grunde besteht (das Streu Pakete von alten Verbindungen, um sicherzustellen, nicht mit neuen Verbindungen stören). Es ist eine bessere Idee, um Ihr Protokoll ein, wo der Client initiiert die Verbindung nahe neu zu gestalten, wenn möglich.
Andere Tipps
Für meinen Vorschlag, bitte den letzten Abschnitt lesen. „Wenn SO_LINGER mit Timeout 0 verwenden“
Bevor wir kommen, dass ein wenig Vortrag über:
- Normale TCP Beendigung
-
TIME_WAIT
-
FIN
,ACK
undRST
Normale TCP Beendigung
Die normalen TCP-Terminierungssequenz sieht wie folgt aus (vereinfacht):
Wir haben zwei Kollegen: A und B
- A ruft
close()
- A sendet
FIN
an B - A geht in
FIN_WAIT_1
Zustand
- A sendet
- B empfängt
FIN
- B sendet
ACK
bis A - B geht in
CLOSE_WAIT
Zustand
- B sendet
- A empfängt
ACK
- A geht in
FIN_WAIT_2
Zustand
- A geht in
- B ruft
close()
- B sendet
FIN
bis A - B geht in
LAST_ACK
Zustand
- B sendet
- A empfängt
FIN
- A sendet
ACK
an B - A geht in
TIME_WAIT
Zustand
- A sendet
- B empfängt
ACK
- B geht an
CLOSED
Zustand - das heißt aus dem Sockel Tabellen entfernt
- B geht an
TIME_WAIT
So der Peer dass Eingeweihte die Kündigung - das heißt Anruf close()
ersten -. Wird bis im TIME_WAIT
Zustand beenden
Um zu verstehen, warum der TIME_WAIT
Zustand ist unser Freund, bitte Abschnitt 2.7 in "UNIX Network Programming" dritte Auflage von Stevens et al (Seite 43) gelesen werden.
Allerdings kann es ein Problem mit vielen Steckdosen in TIME_WAIT
Zustand auf einem Server sein, da es schließlich neue Verbindungen verhindern könnte von akzeptiert werden.
Um dieses Problem umgehen, ich habe viele gesehen, die SO_LINGER Socket-Option mit Timeout 0 vor dem Aufruf close()
einstellen läßt. Dies ist jedoch eine schlechte Lösung, da es die TCP-Verbindung führt mit einem Fehler abgebrochen werden.
Stattdessen entwerfen Sie Ihr Anwendungsprotokoll, so dass der Verbindungsabbruch immer von der Client-Seite initiiert wird. Wenn der Kunde weiß immer, wenn es alle verbleibenden Daten lesen kann er die Terminierungssequenz einzuleiten. Als Beispiel weiß ein Browser aus dem Content-Length
HTTP-Header, wenn es alle Daten gelesen hat und die enge initiieren kann. (Ich weiß, dass in HTTP 1.1 wird es hält es für eine Weile für eine mögliche Wiederverwendung öffnen und schließen Sie es.)
Wenn der Server braucht die Verbindung zu schließen, gestalten das Anwendungsprotokoll, damit der Server den Client Aufruf close()
fragt.
Wann verwendet SO_LINGER mit Timeout 0
Auch nach "UNIX Network Programming" dritte Auflage Seite 202-203, Einstellung SO_LINGER
mit Timeout 0 vor close()
des Aufrufs wird die normale Beendigung Sequenz verursachen nicht eingeleitet werden.
Stattdessen wird die Peer diese Option Einstellung und close()
Aufruf wird eine RST
(Verbindung zurückgesetzt) ??senden, die anzeigt, einen Fehlerzustand und dies ist, wie wird es am anderen Ende wahrgenommen werden. Sie werden in der Regel Fehler wie „Verbindung von Peer zurückgesetzt“ sehen.
Daher wird in der normalen Situation ist es eine wirklich schlechte Idee, Satz SO_LINGER
mit Timeout 0 vor dem Aufruf close()
- von nun an genannt gescheiterten schließen -. In einer Server-Anwendung
Allerdings sind bestimmte Situation erfordert dabei trotzdem:
- Wenn der Kunde von der Serveranwendung misbehaves (Timeout, kehrt ungültige Daten, etc.) eine gescheiterte Nähe Sinn macht in
CLOSE_WAIT
oder enden imTIME_WAIT
Zustand befindet, stecken zu vermeiden. - Wenn Sie Ihre Server-Anwendung neu starten müssen, die derzeit Tausende von Client-Verbindungen hat man bedenkt, könnte diese Socket-Option Einstellung zu vermeiden Tausende von Server-Sockets in
TIME_WAIT
(beim Aufrufclose()
vom Server Ende), da dies den Server von immer verfügbaren Ports für neue Client-Verbindungen verhindern, nachdem neu gestartet werden. - Auf Seite 202 in dem oben erwähnten Buch sagt es ausdrücklich: „Es gibt bestimmte Umstände, die die Verwendung diese Funktion garantieren eine gescheiterte Nähe senden Ein Beispiel ist ein RS-232-Terminal-Server, der für immer in
CLOSE_WAIT
hängen könnte versuchen, Daten zu liefern. zu einem festgefahrenen Terminal-Anschluss, würde aber das steckt Port korrekt zurückgesetzt, wenn er einRST
bekam die anstehenden Daten. " zu verwerfen
Ich würde empfehlen,
Wenn linger ist aber das Timeout Null der TCP-Stack wartet nicht auf Daten anhängig vor dem Schließen der Verbindung gesendet werden. Die Daten können aufgrund dieser verloren, sondern durch linger diese Weise einstellen Sie akzeptieren dies und fordern, dass die Verbindung nicht ordnungsgemäß geschlossen sofort zurückgesetzt werden. Dies bewirkt, dass ein RST eher gesendet werden als die übliche FIN. Dank EJP für seinen Kommentar finden Sie unter hier .
Ob Sie die linger in Ihrem Code sicher zu entfernen oder nicht, hängt von der Art der Anwendung: es ist ein „Client“ (Öffnung TCP-Verbindungen und aktiv erste Schließung) oder ist es ein „Server“ (hört ein TCP offen und es nach der anderen Seite schließen eingeleitet, um die Nähe)?
Wenn Ihre Anwendung hat den Geschmack eines „Client“ (Schluss zuerst) und Sie initiieren und in der Nähe eine große Anzahl von Verbindungen zu verschiedenen Servern (zB wenn Ihre Anwendung ist eine Überwachung der App die Erreichbarkeit einer großen Anzahl von verschiedenen Servern überwacht ) Ihre Anwendung hat das Problem, dass alle Ihre Client-Verbindungen in TIME_WAIT Zustand stecken. Dann würde ich empfehlen, noch Abschaltung anmutig das Timeout auf einen kleineren Wert als die Standardeinstellung zu verkürzen, aber die Client-Verbindungen Ressourcen früher frei. Ich würde das Timeout nicht auf 0 gesetzt, da 0 nicht Abschaltung graziös mit FIN aber gescheiterten mit RST.
Wenn Ihre Anwendung den Geschmack eines „Client“ und hat eine große Anzahl von kleinen Dateien aus dem gleichen Server zu holen, sollten Sie nicht eine neue TCP-Verbindung pro Datei initiieren und in einer riesigen Menge von Client-Verbindungen am Ende in TIME_WAIT, aber halten Sie die Verbindung offen und alle Daten über die gleiche Verbindung holen. Linger Option kann und sollte entfernt werden.
Wenn Ihre Anwendung ein „Server“ ist (an zweiter Stelle als Reaktion auf Peers schließen), auf close () Ihre Verbindung Abschaltung anmutig und Ressourcen befreit werden, wie Sie nicht TIME_WAIT-Zustand. Linger sollten nicht verwendet werden. Aber wenn Ihr Sever App einen Überwachungsprozess Erkennung inaktive offene Verbindungen idleing für eine lange Zeit hat ( „long“ ist definiert werden) Herunterfahren kann diese inaktive Verbindung von Ihrer Seite - sieht es als eine Art Fehlerbehandlung - mit einem mißglückten Abschaltung. Dies geschieht durch linger Timeout auf 0 Schließen () wird dann ein RST an den Client senden, ihm zu sagen, dass Sie sind wütend: -)