Lesen Sie für meinen Vorschlag den letzten Abschnitt: „Wann wird SO_LINGER mit Timeout 0 verwendet?“ .
Bevor wir dazu kommen, ein kleiner Vortrag über:
- Normale TCP-Beendigung
TIME_WAIT
FIN
, ACK
undRST
Normale TCP-Beendigung
Die normale TCP-Beendigungssequenz sieht folgendermaßen aus (vereinfacht):
Wir haben zwei Kollegen: A und B.
- Ein Anruf
close()
- A sendet
FIN
an B.
- A geht in den
FIN_WAIT_1
Zustand
- B erhält
FIN
- B sendet
ACK
an A.
- B geht in den
CLOSE_WAIT
Zustand
- A erhält
ACK
- A geht in den
FIN_WAIT_2
Zustand
- B ruft an
close()
- B sendet
FIN
an A.
- B geht in den
LAST_ACK
Zustand
- A erhält
FIN
- A sendet
ACK
an B.
- A geht in den
TIME_WAIT
Zustand
- B erhält
ACK
- B geht in den
CLOSED
Zustand - dh wird aus den Socket-Tabellen entfernt
ZEIT WARTET
Der Peer, der die Kündigung initiiert - dh close()
zuerst anruft -, landet also im TIME_WAIT
Status.
Um zu verstehen, warum der TIME_WAIT
Staat unser Freund ist, lesen Sie bitte Abschnitt 2.7 in der dritten Ausgabe von "UNIX Network Programming" von Stevens et al. (Seite 43).
Es kann jedoch ein Problem mit vielen Sockets TIME_WAIT
auf einem Server sein, da möglicherweise verhindert wird, dass neue Verbindungen akzeptiert werden.
Um dieses Problem zu umgehen, habe ich viele Vorschläge gesehen, die Socket-Option SO_LINGER mit dem Timeout 0 vor dem Aufruf festzulegen close()
. Dies ist jedoch eine schlechte Lösung, da dadurch die TCP-Verbindung mit einem Fehler beendet wird.
Entwerfen Sie stattdessen Ihr Anwendungsprotokoll so, dass die Verbindungsbeendigung immer von der Clientseite aus initiiert wird. Wenn der Client immer weiß, wann er alle verbleibenden Daten gelesen hat, kann er die Beendigungssequenz initiieren. Ein Browser weiß beispielsweise aus dem Content-Length
HTTP-Header, wann er alle Daten gelesen hat, und kann das Schließen einleiten. (Ich weiß, dass es in HTTP 1.1 für eine mögliche Wiederverwendung eine Weile geöffnet bleibt und dann geschlossen wird.)
Wenn der Server die Verbindung schließen muss, entwerfen Sie das Anwendungsprotokoll so, dass der Server den Client zum Aufrufen auffordert close()
.
Wann wird SO_LINGER mit Timeout 0 verwendet?
Gemäß der dritten Ausgabe von "UNIX Network Programming", Seite 202-203, führt die Einstellung SO_LINGER
mit Timeout 0 vor dem Aufruf close()
dazu, dass die normale Beendigungssequenz nicht initiiert wird.
Stattdessen close()
sendet der Peer, der diese Option einstellt und aufruft , ein RST
(Verbindungs-Reset), das auf einen Fehlerzustand hinweist, und so wird es am anderen Ende wahrgenommen. In der Regel werden Fehler wie "Verbindung durch Peer zurückgesetzt" angezeigt.
Daher ist es in der normalen Situation eine wirklich schlechte Idee, SO_LINGER
vor dem Anruf das Zeitlimit 0 festzulegen close()
- von nun an angerufen eine Serveranwendung abortives Schließen bezeichnet .
Bestimmte Situationen rechtfertigen dies jedoch trotzdem:
- Wenn sich ein Client Ihrer Serveranwendung schlecht verhält (Zeitüberschreitung, Rückgabe ungültiger Daten usw.), ist ein fehlgeschlagener Abschluss sinnvoll, um zu vermeiden, dass er in der Server-Anwendung stecken bleibt
CLOSE_WAIT
oder in dieser endetTIME_WAIT
Status Status .
- Wenn Sie Ihre Serveranwendung neu starten müssen, die derzeit über Tausende von Clientverbindungen verfügt, können Sie diese Socket-Option festlegen, um Tausende von Server-Sockets zu vermeiden
TIME_WAIT
(wenn Sie close()
vom Server aus anrufen ), da dies möglicherweise verhindert, dass der Server verfügbare Ports für neue Clientverbindungen erhält nach dem Neustart.
- Auf Seite 202 des oben genannten Buches heißt es ausdrücklich: "Es gibt bestimmte Umstände, die die Verwendung dieser Funktion zum Senden eines fehlgeschlagenen Abschlusses rechtfertigen. Ein Beispiel ist ein RS-232-Terminalserver, der beim
CLOSE_WAIT
Versuch, Daten an ein feststeckendes Terminal zu liefern , möglicherweise für immer hängen bleibt Port, würde aber den stecken gebliebenen Port ordnungsgemäß zurücksetzen, wenn er RST
die ausstehenden Daten verwerfen müsste . "
Ich würde diesen langen Artikel empfehlen, der meiner Meinung nach eine sehr gute Antwort auf Ihre Frage gibt.