Können TCP- und UDP-Pakete aufgeteilt werden?

41

Können TCP-Pakete stückweise beim Empfänger ankommen?

Wenn ich zum Beispiel 20 Bytes mit dem TCP-Protokoll sende, kann ich dann zu 100% sicher sein, dass ich genau 20 Bytes auf einmal erhalte, nicht 10 Bytes, sondern weitere 10 Bytes oder so?

Und die gleiche Frage für UDP-Protokoll.
Ich weiß, dass UDP unzuverlässig ist und Pakete überhaupt nicht oder in unterschiedlicher Reihenfolge ankommen können, aber was ist mit einem einzelnen Paket? Wenn es eintrifft, kann ich sicher sein, dass es sich um ein vollständiges Paket handelt, nicht um ein Teil?

iamnp
quelle
7
Ein klarer Punkt: Es wird TCP-Segment und UDP-Datagramm genannt. Sie sind keine Pakete. TCP = Segment, UDP = Datagramm, IP = Paket, Ethernet = Frame. Auf allen anderen Ebenen (AFAIK) werden sie nur PDUs (Protocol Data Units) genannt.
Joeqwerty

Antworten:

33

können TCP-Pakete stückweise beim Empfänger ankommen?

Ja. IP unterstützt die Fragmentierung, obwohl TCP im Allgemeinen versucht, die Pfad-MTU zu ermitteln und die Pakete aus Leistungsgründen kleiner als diese zu halten. Die Fragmentierung erhöht die Datenverlustrate katastrophal. Wenn ein Pfad eine Paketverlustrate von 10% aufweist, führt die Fragmentierung eines Datagramms in zwei Pakete zu einer fast 20% igen Datenverlustrate. (Wenn eines der Pakete verloren geht, geht das Datagramm verloren.)

Darüber müssen Sie sich jedoch keine Gedanken machen und die TCP-Schicht auch nicht. Die IP-Schicht setzt Pakete wieder zu ganzen Datagrammen zusammen.

ZB: Wenn ich 20 Bytes über das TCP-Protokoll sende, kann ich dann zu 100% sicher sein, dass ich genau 20 Bytes auf einmal erhalte, nicht 10 Bytes, sondern weitere 10 Bytes oder so?

Nein, aber das hat nichts mit Paketen zu tun. TCP ist im Grunde genommen ein Byte-Stream-Protokoll, bei dem die Grenzen von Anwendungsnachrichten nicht beibehalten werden.

Und die gleiche Frage für UDP-Protokoll. Ich weiß, dass UDP unzuverlässig ist und Pakete überhaupt nicht oder in anderer Reihenfolge ankommen können.

Gleiches gilt für TCP. Pakete sind Pakete. Der Unterschied besteht darin, dass TCP Wiederholungsversuche und Neuanordnungen in das Protokoll integriert hat, UDP jedoch nicht.

aber was ist mit 1 Päckchen? Wenn es eintrifft, kann ich sicher sein, dass es sich um ein vollständiges Paket handelt, nicht um ein Teil?

Nein, aber das ist nicht dein Problem. Das UDP-Protokoll übernimmt das erneute Zusammensetzen von Datagrammen. Das ist ein Teil seiner Arbeit. (Tatsächlich erledigt das IP-Protokoll dies für das UDP-Protokoll. UDP erledigt dies also nur, indem es über IP gelegt wird.) Wenn ein Datagramm auf zwei Pakete aufgeteilt wird, setzt das IP-Protokoll es für das UDP-Protokoll wieder zusammen, so dass Sie wird die vollständigen Daten sehen.

David Schwartz
quelle
10
Für Anfänger könnte es sich lohnen, das letzte Detail zu klären: Sie sehen die vollständigen Daten für das betreffende Datagramm . Wenn eines der aufgeteilten Pakete verloren geht, geht das Datagramm verloren und die UDP-Schicht wird es nie erfahren. Solange alle Pakete im Datagramm empfangen werden, werden sie auf der IP-Ebene zusammengestellt und dann an die UDP-Ebene weitergeleitet. Dies schließt nicht aus, dass "Chunks" im Datenstrom fehlen. Um kein Pedant zu sein, aber als ich dieses Zeug lernte, erkannte ich den Unterschied zwischen IP-Fragment und UDP-Verlust erst beim zweiten oder dritten Durchgang durch das Lehrbuch.
Justin ᚅᚔᚈᚄᚒᚔ
20

Sie können nicht sicher sein, dass sie wirklich physisch sofort ankommen. Die Datenverbindungsschichten unter TCP / UDP können Ihr Paket aufteilen, wenn sie dies möchten. Insbesondere wenn Sie Daten über das Internet oder ein Netzwerk senden, auf das Sie keinen Einfluss haben, ist dies schwer vorherzusagen.

Aber egal ob die Daten in einem Paket oder in mehreren Paketen beim Empfänger ankommen. Das Betriebssystem sollte die Verkettung dieser Pakete abstrahieren, sodass es für Ihre Anwendung immer noch so aussieht, als wäre alles auf einmal angekommen. Wenn Sie also kein Kernel-Hacker sind, müssen Sie sich in den meisten Fällen keine Sorgen machen, wenn diese Daten in einem oder mehreren Paketen übertragen werden.

Für UDP führt das Betriebssystem auch eine Abstraktion durch, sodass die Anwendung, die die Daten empfängt, nicht wissen muss, in wie vielen Paketen die Daten übertragen wurden. Der Unterschied zu TCP besteht jedoch darin, dass es keine Garantie dafür gibt, dass die Daten tatsächlich eintreffen. Es ist auch möglich, dass die Daten in mehrere Pakete aufgeteilt werden, von denen einige eintreffen und andere nicht. Für die empfangende Anwendung sieht es sowieso nur aus wie ein Datenstrom, egal ob er vollständig ist oder nicht.

Wiederholung
quelle
Kümmert sich der Netzwerkkartentreiber nicht darum, Pakete wieder zusammenzusetzen, die nicht der Kernel sind?
Bluehallu
2
@Hallucynogenyc: Sofern sich nichts ändert, ist das Internetprotokoll so konzipiert, dass Pakete mit mehr als 576 Bytes zu jedem Zeitpunkt auf ihrer Reise aufgeteilt werden können. Es wird jedoch nur vom Endempfänger erwartet, dass sie neu kombiniert werden. Ich denke, die Idee ist, dass die Verwendung größerer Pakete in den meisten Fällen ein Versuch war, den Overhead zu reduzieren. Sobald ein Paket zu einem bestimmten Zeitpunkt auf der Reise aufgeteilt wurde, ist der Overhead bereits angefallen. Dies führt zu einer erneuten Vereinigung, bevor der Endempfänger irgendetwas ändern kann. Dies kann zu Verletzungen führen, wenn es erneut aufgeteilt werden muss.
Supercat
Ich glaube, dass, während jedes Paket, das über 576 Bytes ist, aufgeteilt werden kann, Pakete, die unter dieser Größe sind, möglicherweise nicht; Eingebettete Systeme, die keine geteilten Pakete verarbeiten können, sollten es vermeiden, nach etwas Größerem zu fragen.
Supercat
1
@ mauro.stettler: Ich habe einen TCP-Stack auf "Bare Metal" geschrieben (Schreiben des Codes, um direkt mit einer Reihe von Netzwerkschnittstellen-Chips zu kommunizieren). Für Hardware, die mit einer Verbindung mit einer Beschränkung von 576 Byte kommuniziert, ist das Teilen längerer Pakete einfach. Das Zusammensetzen von Paketen ist viel komplizierter, zumal man möglicherweise Teile von vielen verschiedenen Paketen erhält, bevor eines davon vollständig empfangen wird.
Superkatze
Es besteht die Hoffnung, dass es nicht für winzige Nutzlasten aufgeteilt wird (ungefähr 10 oder 20 Bytes sollten in Ordnung sein), da für jeden Hop für IP-Pakete unter IPv4 eine "garantierte maximale Größe" erforderlich ist : mindestens 68 Bytes (einschließlich IP-Header und Header auf niedrigerer Ebene nicht mitgerechnet). Siehe die erste Tabelle in de.wikipedia.org/wiki/Maximum_transmission_unit . Abweichend von den 576 Bytes minimaler Größe, die für die HOSTS erforderlich sind (dh der Ursprung oder das Ende der Übertragung, nicht alle Zwischen-Hops). Und Vorsicht: Die Nutzlast ist immer noch geringer (da die Überschriften jeder Ebene etwas Platz beanspruchen).
Olivier Dulac
14

Beispiele. Blöcke von zusammenhängenden Zeichen entsprechen send () -Aufrufen:

TCP:

Send: AA BBBB CCC DDDDDD E         Recv: A ABB B BCC CDDD DDDE

Alle gesendeten Daten werden in der richtigen Reihenfolge empfangen, jedoch nicht unbedingt in denselben Blöcken.

UDP:

Send: AA BBBB CCC DDDDDD E         Recv: CCC AA E

Die Daten müssen nicht unbedingt in der gleichen Reihenfolge vorliegen und überhaupt nicht empfangen werden, aber die Nachrichten bleiben in ihrer Gesamtheit erhalten.

Jim Cote
quelle
5

ZB: Wenn ich 20 Bytes über das TCP-Protokoll sende, kann ich dann zu 100% sicher sein, dass ich genau 20 Bytes auf einmal erhalte, nicht 10 Bytes, sondern weitere 10 Bytes oder so?

Nein, TCP ist ein Stream-Protokoll. Es hält die Daten in der richtigen Reihenfolge, gruppiert sie jedoch nicht nach Nachrichten. Auf der anderen Seite ist UDP nachrichtenorientiert, aber unzuverlässig. SCTP bietet das Beste aus beiden Welten, ist jedoch nicht nativ verwendbar, da NATs das Internet beschädigen.

Changaco
quelle
1

Es besteht die Gewissheit, dass beim Senden von 20 Bytes am Anfang eines TCP-Streams keine zwei 10-Byte-Teile eingehen. Dies liegt daran, dass der TCP-Stack keine so kleinen Segmente sendet: Es gibt eine minimale MTU-Größe. Befindet sich der Send jedoch irgendwo in der Mitte eines Streams, sind alle Wetten deaktiviert. Es kann sein, dass Ihr Protokollstapel 10 Byte der Daten benötigt, um ein Segment zu füllen und auszusenden, und dann die nächsten 10 Byte in ein anderes Segment gehen.

Ihr Protokollstapel zerlegt Daten in Blöcke und stellt sie in eine Warteschlange. Die Blockgrößen basieren auf dem Pfad MTU. Wenn Sie einen Sendevorgang ausführen und noch Daten in der Warteschlange anstehen, wird der Protokollstapel in der Regel das Segment am Ende der Warteschlange überprüfen und feststellen, ob in diesem Segment Platz zum Hinzufügen weiterer Daten vorhanden ist. Der Raum kann so klein wie ein Byte sein, so dass sogar ein Zwei-Byte-Send in zwei Teile aufgeteilt werden kann.

Am anderen Ende bedeutet die Segmentierung von Daten, dass es teilweise Lesevorgänge geben kann. Eine Empfangsoperation kann möglicherweise aktiviert werden und Daten abrufen, wenn nur ein Segment eintrifft. In der weit verbreiteten Sockets-API kann ein Empfangsaufruf nach 20 Bytes fragen, er kann jedoch mit 10 zurückkehren. Natürlich kann eine Pufferschicht darauf aufgebaut werden, die blockiert, bis 20 Bytes empfangen werden oder die Verbindung unterbrochen wird. In der POSIX-Welt kann diese API die Standard-E / A-Datenströme sein: Sie können fdopeneinen Socket-Deskriptor zum Abrufen eines FILE *Datenstroms verwenden, freadum einen Puffer so zu füllen, dass die vollständige Anforderung mit so vielen readAufrufen wie nötig erfüllt wird .

UDP-Datagramme rahmen die Daten ein. Jeder Sendeaufruf generiert ein Datagramm (siehe unten zum Verkorken). Die andere Seite empfängt ein vollständiges Datagramm (und in der Socket-API muss ein Puffer angegeben werden, der groß genug ist, um es aufzunehmen, da das Datagramm sonst abgeschnitten wird). Große Datagramme werden durch IP-Fragmentierung fragmentiert und für Anwendungen transparent neu zusammengestellt. Wenn ein Fragment fehlt, geht das gesamte Datagramm verloren. In dieser Situation können keine Teildaten gelesen werden.

Es gibt Erweiterungen für die Schnittstelle, mit denen mehrere Operationen ein einzelnes Datagramm angeben können. Unter Linux kann ein Socket "verkorkt" werden (das Senden wird verhindert). Während des Verkorkens werden geschriebene Daten zu einer Einheit zusammengefasst. Wenn der Socket dann "entkorkt" ist, kann ein einzelnes Datagramm gesendet werden.

Kaz
quelle
Das ist falsch: Wenn man ein Paket mit einer Nutzlast von 10 oder 20 Bytes sendet, wird 1 Paket generiert, und (wie oben erwähnt) sollte es bei Verwendung von ipv4 auch dann passen, wenn alle Header der anderen Protokollebenen hinzugefügt werden in innerhalb von 68 Bytes, um sicherzustellen, dass es alle Hops in 1 Paket durchläuft. Der TCP-Stack wird nicht (wie in Ihrem ersten Absatz angedeutet) "warten, bis die MTU gefüllt ist (dh mehrere Pakete hinzufügen, um ein Paket mit der richtigen Größe zu erstellen)", um ein Paket zu senden! ... Dieses Verhalten würde viele Dinge zerstören ( (auch wenn diese "Fragmente" von & an dasselbe
Olivier Dulac
@OlivierDulac: Das ist falsch. TCP generiert normalerweise Pakete nach Bedarf, um die Netzwerknutzung zu optimieren, sodass 20 Byte in zwei verschiedenen Paketen enden können, wie von Kaz erläutert. Dies kann mithilfe der Socket-Option TCP_NODELAY gesteuert werden, mit der der Nagles-Algorithmus deaktiviert wird, mit dem Bytes an Pakete gesendet werden, wenn Ihre Anwendung ein schnelleres TCP-Netzwerk benötigt. Außerdem sind 68 Bytes keineswegs der De-facto-Standard für die Paketlänge: 1500 Bytes sind ein üblicherer Standardwert (dies variiert tatsächlich zwischen den Netzwerken).
jjmontes