Frage Wenn ein TCP-Paket teilweise bestätigt wurde, wie wird der Mechanismus der erneuten Übertragung reagieren?


Wenn ein TCP-Client ein Paket mit der Sequenznummer von 10000 bis 20000 an einen TCP-Server sendet. Der TCP antwortet mit einem ACK mit Seq_ack 20001.

Wenn ich das TCP-Paket vom Client abfangen und das Paket in 2 TCP-Segmente aufteilen, eins mit Seq von 10000 bis 15000 und das andere mit Seq von 15001 bis 20000. Und dann werden diese 2 TCP-Segmente an den TCP-Server gesendet. Angenommen, das zweite Segment ist im Pfad verloren. Der TCP-Server antwortet eine ACK mit Seq_ack 15001.

Jetzt, da der TCP-Client ein integrales Paket mit Seq 10000 bis 20000 sendet, aber ein ACK mit 15001 erhält, ist dies vom Standpunkt des Clients aus merkwürdig. Wie wird es reagieren? Theoretisch sollte der Client die Bytes von Seq. 15001 bis 20000 erneut übertragen, dh der Client wird neue Pakete von Seq. 15001 übertragen. Aber wie steht es mit der Praxis, bei TCP-Stack-Implementierung ist es das gleiche wie in der Theorie?

Ich denke, im TCP-Sendepuffer, wenn ein TCP-Segment gesendet wird, bleibt das Segment dort bis zum ACK. Wenn das ACK kommt, werden diese Bytes für das Segment aus dem Puffer gelöscht. Es gibt einen Zeiger im Sendepuffer, wenn ein ACK kommt, zeigt der Zeiger auf den Ort, dem der ack_seq entspricht. Die Bytes unterhalb des ack_seq werden gelöscht. Auf diese Weise muss das gesamte Segment nicht erneut übertragen werden?


12
2018-05-22 12:57


Ursprung




Antworten:


Das nennt man selektive Bestätigungund ist bereits in der TCP - Spezifikation enthalten, die in RFC 2018. Dies würde dem Client ermöglichen, tatsächlich nur die Bytes 15001 bis 20000 erneut zu senden (da sie sich in verschiedenen Paketen / Segmenten befinden) ob Sie haben sie geteilt, wie Sie sagen), aber interessanterweise können sogar Quittierungen außerhalb der Reihenfolge zugelassen werden.

Von RFC 2018:

Wenn ein ACK empfangen wird, der eine SACK-Option enthält, SOLLTE der Datensender die selektive Bestätigung für zukünftige Referenz aufzeichnen. Es wird angenommen, dass der Datensender eine Wiederholungsübertragungswarteschlange hat, die die Segmente enthält, die übertragen wurden, aber noch nicht bestätigt wurden, und zwar in Reihenfolge der Sequenznummern.

Unterstützen SACK ist nicht wird von der TCP-Spezifikation benötigt. Wenn entweder der Kunde oder der Server unterstützte die selektive Bestätigung nicht, tatsächlich müssten alle Bytes 10000 bis 20000 erneut übertragen werden.

In TCP-Stack-Implementierung, ist es das gleiche wie in der Theorie?

Gewöhnlich SACK  ist unterstützt, da die Performance-, Effizienz- und Latenzgewinne signifikant sind - insbesondere in einem Netzwerk wie dem Internet.

In der Tat sollten diese Annahmen auch dann gelten, wenn Sie die Pakete manuell wie angegeben manipulieren. Nach RFC 793mindestens muss das gesamte Datenfenster erneut übertragen werden, aber der Empfänger tut wissen, dass die empfangenen Daten mindestens sind gültig. Für Details zur Implementierung, Abschnitt 3.3 - Sequenznummernvon RFC 793.

Einen Überblick über den gesamten Prozess mit und ohne selektive Bestätigung Unterstützung, siehe Dieser Artikel (enthält einige sehr nützliche Diagramme).


8
2018-05-22 13:04



es ist ein bisschen seltsam für mich, weil TCP Stream-basierte, Byte-orientierte Protokoll ist. Warum sollte es das gesamte Segment erneut übertragen? Es scheint mir, dass TCP ohne SAKC Segment-orientierte Stream-Protokoll ist, aber TCP mit Sack ist real Byte-orientiert. Ich denke, das RFC geht nicht speziell darauf ein. - misteryes
Wie der TCP-Stack seinen Sendepuffer verwaltet, ist das gleiche wie das, was ich in der aktualisierten Frage geschrieben habe. - misteryes
@misteryes Dieser Artikel umreißt den Prozess (mit einigen großen Diagrammen auch!). - Breakthrough
In dem von Ihnen empfohlenen Link scheint der Autor das Problem noch segmentorientiert und nicht in Byte-orientierter Weise zu diskutieren. Ist es nicht? - misteryes
Ich kannte SACK, bevor ich diese Frage stelle. Ganz am Anfang glaube ich nicht, dass SACK etwas mit dieser Frage zu tun hat. Wenn TCP nicht byteorientiert, sondern segmentorientiert ist, sollte SACK meiner Meinung nach auch gleich sein. Der Unterschied zwischen SACK-aktiviert und SACK-deaktiviert ist, dass TCP mit SACK eine Sequenz-Lücke in ack_seq erlaubt. Aber ich dachte, das Sequenzloch entspricht einem Segment. während nach Ihrem Sprichwort, das Loch kann die Hälfte / ein Teil eines Segments sein. - misteryes


Segmentgrößen können (und tun) sich über die Lebensdauer einer Verbindung ändern. Glücklicherweise muss TCP die Segmentgröße, mit der einzelne Pakete zuvor gesendet wurden, nicht aufzeichnen. Daher wird es Folgendes tun:

  1. Immer wenn ein ACK ankommt, führe den Zeiger entsprechend auf das erste unbestätigte Byte und verwerfe jeden jetzt nicht benötigten Puffer.
  2. Wenn die Notwendigkeit einer erneuten Übertragung besteht (Fast Retransmit oder Timeout; NICHT sofort nach dem Erhalt der ersten ACK!), wird es erneut in der aktuell gültige Segmentgröße beginnend mit dem Zeiger auf das erste unbestätigte Byte.

Beide Operationen werden unabhängig von der Segmentgröße ausgeführt, in die diese Bytes ursprünglich gesendet wurden. Daher sollte die Theorie zu den meisten Implementierungen passen.

Lassen Sie mich einige Hintergründe erläutern:

Verwendet TCP Bytes oder Segmente? Für die Anwendung stellt TCP eine Byte-Stream-Schnittstelle bereit. Außerdem sind alle Header-Felder und internen Variablen in Bytes. Um jedoch Informationen zu übertragen, zerlegt TCP sie in Segmente, da das Senden von Bytes eins nach dem anderen ziemlich verschwenderisch wäre :-). Die Verwendung von Byte-Zählern überall hat den Vorteil, dass die Segmentgröße nicht über die Lebensdauer der Verbindung konstant bleiben muss:

  • Optionen werden eingeführt, z. Huckepack mit einem SACK auf einem Retransmit (reale Implementierungen werden dies selten, wenn überhaupt, treffen)
  • Die Pfad-MTU ändert sich z.B. Eine Verbindung entlang des Pfads ändert sich zu einer niedrigeren MTU, oder die Engpass MTU-Verbindung wird ausgelöst. Dies passiert, wenn Tunnel eingerichtet werden (VPN, PPPoE) oder das Routing-Protokoll eine andere MTU-Verbindung auswählt. Dies geschieht in IPv4 mit Do not Fragment (für die meisten modernen TCPs); immer in TCPv6).

BTW: SACK ist hier nicht die Antwort, da der Empfänger (typischerweise) nur SACK benutzt, wenn er a erkennt Loch im Byte-Stream (d. h. wenn ein Paket verloren gegangen ist, aber ein folgendes Paket angekommen ist).


3
2018-06-05 12:01