Zum Hauptinhalt springen

Ein weit verbreiteter Irrtum ist, dass TCP die Zustellung der Daten garantiert. Tatsächlich garantiert TCP jedoch nur, dass die Daten an den TCP-Stack des empfangenden Hosts zugestellt werden oder dass ein Fehler an die sendende Anwendung gemeldet wird. Leider gibt der Fehlerbericht keinen Aufschluss darüber, wie viele Daten tatsächlich zugestellt wurden. Außerdem besteht ein wesentlicher Unterschied zwischen dem empfangenden TCP-Stack und der empfangenden Anwendung.

Es gibt zwei grundlegende Fehlerszenarien. Im ersten Fall empfängt der sendende TCP-Stack keine TCP-Bestätigungen für die Daten, die er überträgt. In diesem Szenario kann die sendende Anwendung weiterhin „send“ aufrufen, um weitere Daten in den Sendepuffer des TCP-Stacks zu stellen. Sobald der TCP-Stack die Übertragung aufgrund einer Zeitüberschreitung abbricht, gibt der nächste von der sendenden Anwendung aufgerufene „send“- (oder „receive“-)Befehl den Fehler „ETIMEDOUT“ zurück. Die Anwendung weiß nun, dass ein Problem aufgetreten ist, hat jedoch keine Ahnung, wie viele Daten erfolgreich übertragen wurden. Erfolgreich bedeutet, dass der sendende TCP-Stack eine Bestätigung für die Daten vom empfangenden TCP-Stack erhalten hat.

Im zweiten Szenario überträgt der sendende TCP-Stack Daten und erhält statt einer Bestätigung einen Reset. Der Reset kann darauf hinweisen, dass der empfangende TCP-Stack den Socket geschlossen hat oder dass ein Netzwerkgerät, möglicherweise eine Firewall, eine Zeitüberschreitung festgestellt hat. Wenn die sendende Anwendung das nächste Mal „send“ (oder „receive“) aufruft, wird der Fehler ECONNRESET angezeigt. Man könnte meinen, dass die sendende Anwendung in diesem Szenario daraus schließen könnte, dass nur die Daten aus dem letzten Send-Aufruf fehlgeschlagen sind, aber das wäre falsch. Es ist möglich, dass der sendende TCP-Stack die Daten aus mehreren Send-Aufrufen in einem TCP-Segment gepuffert hat und dass dieses Segment den Reset ausgelöst hat, oder dass eine Reihe von TCP-Segmenten gesendet wurde, bevor der Reset, ausgelöst durch das erste Segment in der Reihe, beim Sender angekommen ist. Die sendende Anwendung kann lediglich daraus schließen, dass nicht alle Daten erfolgreich übertragen wurden.

Es gibt ein drittes Fehlerszenario, das nichts mit dem TCP-Stack (Senden oder Empfangen) oder dem Netzwerk zu tun hat. Angenommen, die empfangende Anwendung hat einen Fehler, der sie daran hindert, die Daten zu lesen. Der empfangende TCP-Stack empfängt weiterhin die Daten und sendet TCP-Bestätigungen, bis der TCP-Empfangspuffer voll ist. Das können jedoch bis zu 64 KB Daten sein (oder mehr, wenn TCP-Window-Scaling unterstützt wird). Wenn die empfangende Anwendung neu gestartet werden muss, gehen alle Daten im TCP-Empfangspuffer verloren. Der empfangende TCP-Stack sollte (muss aber nicht) einen Reset an den sendenden TCP-Stack senden, wenn die empfangende Anwendung beendet wird. Er sendet einen Reset, sobald er das nächste Mal ein Segment für die nun geschlossene Verbindung empfängt. Aus Sicht der sendenden Anwendung ähnelt dies dem zweiten Szenario. Es wird jedoch darauf hingewiesen, dass selbst wenn der empfangende TCP-Stack die Daten bestätigt, es für den Sender im Falle eines Fehlers nicht sicher ist, davon auszugehen, dass die empfangende Anwendung die Daten gelesen hat.

Die Erkenntnis, die man aus diesen Fehlerszenarien ziehen kann, ist, dass ohne eine Bestätigung auf Anwendungsebene ein Übertragungszeitüberschreitung oder ein Reset-Fehler darauf hindeutet, dass einige oder möglicherweise alle übertragenen Daten von der empfangenden Anwendung nicht gelesen wurden. Aus diesem Grund empfehle ich, dass alle Anwendungen Bestätigungen auf Anwendungsebene enthalten, darauf vorbereitet sind, eine Verbindung wiederherzustellen und nicht bestätigte Daten erneut zu übertragen, und in der Lage sind, mit doppelten Daten umzugehen, da möglicherweise die Bestätigung verloren gegangen ist.