Vor VOS 17.1 akzeptierte STCP eine TCP-Verbindungsanforderung erst dann, wenn die Server-Anwendung die accept-Funktion aufgerufen hatte. Verbindungsanforderungen wurden in eine Backlog-Warteschlange gestellt, aber keine Antwort wurde gesendet, bis ein Accept-Aufruf die Anforderung aus der Backlog-Warteschlange entfernte. Sobald die Backlog-Warteschlange gefüllt war, sendete STCP als Antwort auf eine Verbindungsanforderung einen Reset.
Ab Version 17.1 hat sich die Dynamik von TCP-Verbindungen geändert. Wenn nun eine Verbindungsanforderung eingeht, sendet der STCP-Stack unter der Annahme, dass die Backlog-Warteschlange noch nicht gefüllt ist, sofort eine Antwort, die die Verbindung annimmt. Die Verbindung wird dann in die Backlog-Warteschlange gestellt. Sobald die Backlog-Warteschlange gefüllt ist, wird auf nachfolgende Verbindungsanfragen keine Antwort mehr gesendet. Wenn die Serveranwendung accept aufruft, wird die Verbindung an der Spitze der Backlog-Warteschlange entfernt. Dieses Verhalten ähnelt nun dem Verhalten von TCP-Stapeln auf den meisten anderen Betriebssystemen.
Unter normalen Umständen führt diese Änderung der Dynamik zu keiner merklichen Änderung im Verhalten der Server- oder Client-Anwendungen. Wenn sich jedoch die Serveranwendung verlangsamt oder Verbindungen schneller als erwartet eingehen, können Verbindungen für längere Zeit in der Backlog-Warteschlange bleiben. Unter diesen Umständen können einige interessante Verhaltensweisen festgestellt werden.
Die folgende Tabelle gibt einen Überblick darüber, was passiert, wenn eine Verbindungsanforderung in die Backlog-Warteschlange gestellt wird, basierend auf den Aktionen des Clients. Der Client kann nichts tun und darauf warten, dass die Serveranwendung Daten sendet, er kann Daten senden und/oder er kann die Verbindung entweder mit einem FIN- (final) Flag (normales Schließen) oder einem RST- (reset) Flag (anormales Schließen) schließen. Die ersten 4 Spalten verhalten sich so, wie Sie es erwarten. Die Serveranwendung ruft accept auf, um einen Socket aus der Backlog-Warteschlange zu erhalten, ruft dann recv auf und bleibt entweder hängen, wenn keine Daten vorhanden sind, oder erhält Daten und/oder einen Hinweis auf das Ende der Datei, je nachdem, was sich im Socket befindet. Es sind die letzten 4 Spalten, die genauer betrachtet werden müssen.
Nichts in der Steckdose | Daten in der Buchse | FIN in der Steckdose | Daten in der Buchse/
FIN in der Steckdose |
Daten in der Buchse/
FIN in der Buchse/ Client-Buchse weg |
FIN in der Buchse/
Client-Buchse weg |
Daten in der Buchse/
Reset gesendet |
Senden zurücksetzen | ||
Akzeptieren | Rückgabe Buchse | Rückgabe Buchse | Rückgabe Buchse | Rückgabe Buchse | Rückgabe Buchse | Rückgabe Buchse | Hängt | Hängt | |
Erster Rückruf | Hängt | Liefert Daten | Gibt EOF zurück | Liefert Daten | Gibt Reset-Fehler zurück | Gibt EOF zurück | |||
Zweiter Recv | Hängt | Gibt EOF zurück |
Daten im Socket / FIN im Socket / Client-Socket weg
In diesem Szenario hat der Client einige Daten gesendet und die Verbindung abgebaut. Die Version 17.1 von STCP bestätigt alle gesendeten Daten, bestätigt aber das FIN erst, wenn die Daten in der Empfangswarteschlange an die Anwendung übergeben wurden. Infolgedessen wird das FIN des Clients erneut übertragen, bis der Timer für die erneute Übertragung des Clients abläuft. Eine gut geschriebene Client-Anwendung wartet darauf, dass die Server-Anwendung ihre Seite der Verbindung schließt, so dass der Client über einen Fehler informiert wird, wenn das FIN abläuft. Wenn die Client-Anwendung jedoch einfach den Socket schließt, ohne auf eine Meldung des Servers zu warten, weiß sie nicht, dass die gesendeten Daten möglicherweise verloren gegangen sind.
Wenn die Serveranwendung aufruft, wird ein doppeltes Acknowledgement-Paket akzeptiert, das die Daten, aber nicht das FIN, bestätigt. Da der Client seinen Socket abgerissen hat, antwortet er mit einem Reset. Das Reset löscht den Socket auf der Serverseite. Die Serveranwendung erhält entweder beim ersten oder zweiten Aufruf von recv einen Reset-Fehler, abhängig von der Zeit zwischen dem Aufruf von accept und dem Aufruf des ersten recv. Wenn diese Zeit schneller ist als die Zeit, die benötigt wird, um das Reset-Paket des Clients zu erhalten und zu verarbeiten, sieht die Server-Anwendung die Daten. In jedem Fall weiß die Serveranwendung, dass eine Verbindung hergestellt wurde und dass sie abgebrochen wurde.
FIN im Socket / Client-Socket weg
Der Unterschied zum vorherigen Szenario besteht darin, dass keine Daten im Socket vorhanden sind. Wenn keine Daten vorhanden sind, wird das FIN quittiert. Der accept gibt den Socket zurück und der recv gibt ein EOF zurück, das anzeigt, dass er das FIN empfangen hat. Jeder Versuch, in den Socket zu schreiben, einschließlich des Schließens, führt dazu, dass ein Reset zurückgegeben wird, da der Client nicht mehr über den entsprechenden Socket verfügt.
Daten im Socket / Reset gesendet
Hier sendet der Client einige Daten und sendet dann einen Reset. Es kann viele Gründe für den Reset geben; ein häufiger ist, dass die Anwendung den Socket abbaut und der TCP-Stack entweder sofort einen Reset sendet oder einen Reset sendet, nachdem er keine Bestätigung für das FIN-Paket erhalten hat. Dies ist ähnlich wie das erste Szenario, aber der TCP-Stack des Clients sendet einen Reset, bevor er seinen Socket abbaut, anstatt nur den Socket abzubauen. Auch hier wird eine gut geschriebene Client-Anwendung dies als Fehler erkennen; eine nicht so gut geschriebene Anwendung wird keinen Fehler erkennen.
Der Server-Socket wird abgerissen und alle Daten werden verworfen, wenn das Zurücksetzen empfangen wird, so dass die Server-Anwendung nicht einmal einen Hinweis darauf sieht, dass jemals eine Verbindung hergestellt wurde; sie bleibt einfach hängen und wartet auf eine weitere Verbindung.
Reset gesendet
Auch hier entfernt das Zurücksetzen den Socket effektiv aus der Backlog-Warteschlange, so dass der Accept ihn nicht sieht und auf eine weitere Verbindungsanforderung wartet.
Was bedeutet das alles also wirklich? Erstens erhalten Client-Anwendungen jetzt möglicherweise eine schnellere Verbindungsantwort, müssen aber möglicherweise länger auf jede Art von Banner oder Meldung auf Anwendungsebene warten. Eventuelle Timeouts für diese Banner/Nachrichten müssen eventuell nach oben angepasst werden. Zweitens müssen Server-Applikationen darauf vorbereitet sein, einen Fehler aus dem recv-Aufruf unmittelbar nach einem accept-Aufruf zu behandeln. Dies war schon immer eine Möglichkeit, aber die Wahrscheinlichkeit ist jetzt größer. Schließlich sollten Client-Anwendungen, die Daten an den Server senden und keine Rückmeldung erwarten, so geschrieben werden, dass sie bestätigen, dass die Server-Anwendung die Verbindung korrekt beendet hat, oder sie riskieren, unwissentlich Daten zu verlieren. Auch diese Möglichkeit hat es schon immer gegeben und ist nicht einzigartig für STCP, aber die Wahrscheinlichkeit ist jetzt etwas größer.