Frage Können TCP- und UDP-Pakete in Teile aufgeteilt werden?


Können TCP-Pakete stückweise zum Empfänger gelangen?

Zum Beispiel, wenn ich 20 Bytes unter Verwendung des TCP-Protokolls sende, kann ich 100% sicher sein, dass ich genau 20 Bytes auf einmal empfangen werde, nicht 10 Bytes, dann noch 10 Bytes oder so?

Und die gleiche Frage für UDP-Protokoll.
Ich weiß, dass UDP unzuverlässig ist und Pakete überhaupt nicht ankommen oder in anderer Reihenfolge ankommen können, aber was ist mit einem einzelnen Paket? Wenn es ankommt, kann ich sicher sein, dass es ein komplettes Paket ist, kein Stück?


37
2017-08-27 10:02


Ursprung


Ein Punkt der Klarstellung: Es wird ein TCP-Segment und ein UDP-Datagramm genannt. Sie sind keine Pakete. TCP = Segment, UDP = Datagramm, IP = Paket, Ethernet = Frame, Bei allen anderen Layern (AFAIK) werden sie nur PDUs (Protocol Data Units) genannt. - joeqwerty


Antworten:


Können TCP-Pakete zu Stücken ankommen?

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

Sie müssen sich jedoch nicht darum kümmern, und auch nicht die TCP-Schicht. Die IP-Schicht setzt Pakete zu ganzen Datagrammen zusammen.

Beispiel: Wenn ich 20 Bytes mit dem TCP-Protokoll sende, kann ich 100% sicher sein, dass ich genau 20 Bytes auf einmal bekomme, nicht 10 Bytes, dann noch 10 Bytes oder so?

Nein, aber das hat nichts mit Paketen zu tun. TCP ist im Grunde genommen ein Byte-Stream-Protokoll, das die Anwendungsnachrichtengrenzen nicht bewahrt.

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

Das Gleiche gilt für TCP. Pakete sind Pakete. Der Unterschied besteht darin, dass TCP Wiederholungen und Neuanordnungen in das Protokoll eingebaut hat, während UDP dies nicht tut.

aber was ist mit 1 Paket? Wenn es ankommt, kann ich sicher sein, dass es ein komplettes Paket ist, kein Stück?

Nein, aber das ist nicht dein Problem. Das UDP-Protokoll behandelt das Zusammensetzen von Datagrammen. Das ist Teil seiner Arbeit. (Tatsächlich macht das IP-Protokoll dies für das UDP-Protokoll, also UDP tut es einfach, indem es auf IP überlagert wird.) Wenn ein Datagramm über zwei Pakete aufgeteilt wird, wird das IP-Protokoll es für das UDP-Protokoll wieder zusammensetzen wird die vollständigen Daten sehen.


29
2017-08-27 10:27



Könnte es wert sein, das letzte bisschen für Anfänger Leser zu klären: Sie werden die vollständigen Daten sehen  für das betreffende Datagramm. Wenn eines der aufgeteilten Pakete verloren geht, ist das Datagramm verloren und die UDP-Schicht wird es nie erfahren. Solange alle Pakete im Datagramm empfangen werden, werden sie auf der IP-Schicht zusammengefügt und dann an die UDP-Schicht übergeben. Dies schließt nicht die Möglichkeit aus, "Blöcke" im Datenstrom zu verpassen. Nicht, um ein Pedant zu sein, aber als ich dieses Zeug lernte, habe ich den Unterschied zwischen IP frag und UDP-Verlust bis zum 2. oder 3. Durchlauf durch das Lehrbuch nicht gefunden. - Justin ᚅᚔᚈᚄᚒᚔ


Sie können nicht sicher sein, dass sie wirklich physisch auf einmal ankommen. Die Datenlink-Layer unterhalb von TCP / UDP können Ihr Paket bei Bedarf aufteilen. Besonders wenn Sie Daten über das Internet oder andere Netzwerke außerhalb Ihrer Kontrolle senden, ist es schwer vorherzusagen.

Aber egal, ob die Daten in einem Paket oder mehreren Paketen beim Empfänger ankommen. Das Betriebssystem sollte die Verkettung dieser Pakete abstrahieren, so dass 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 Gedanken darüber machen, ob diese Daten in einem oder mehreren Paketen übertragen werden.

Für UDP wird das Betriebssystem auch einige Abstraktionen durchführen, so dass die Anwendung, die die Daten empfängt, nicht wissen muss, in wie vielen Paketen die Daten übertragen wurden. Aber der Unterschied zu TCP besteht darin, dass es keine Garantie dafür gibt, dass die Daten tatsächlich ankommen. Es ist auch möglich, dass die Daten in mehrere Pakete aufgeteilt werden und einige von ihnen ankommen und andere nicht. Für die empfangende Anwendung sieht es sowieso wie ein Datenstrom aus, egal ob es vollständig ist oder nicht.


19
2017-08-27 10:04



Versucht der Netzwerkkartentreiber nicht, Pakete neu zusammenzusetzen, nicht den Kernel? - bluehallu
@Hallucynogenyc: Sofern sich die Dinge nicht geändert haben, ist das Internet-Protokoll so ausgelegt, dass Pakete mit mehr als 576 Bytes an jedem Punkt ihrer Reise aufgeteilt werden können, erwartet aber nichts anderes als den letzten Empfänger, der sie neu kombiniert. Ich denke, die Idee ist, dass die Verwendung von größeren Paketen in den meisten Fällen eine Bemühung war, den Overhead zu reduzieren; Sobald ein Paket an irgendeinem Punkt seiner Reise aufgeteilt wurde, ist der Overhead bereits entstanden, so dass eine Rekombination stattfindet, bevor der endgültige Empfänger nichts helfen kann und möglicherweise Schaden anrichten kann, wenn er erneut aufgeteilt werden muss. - supercat
Ich glaube, dass Pakete, die über 576 Bytes liegen, aufgeteilt werden können, Pakete, die unter dieser Größe liegen, nicht. Eingebettete Systeme, die keine geteilten Pakete verarbeiten können, sollten vermeiden, nach etwas Größerem zu fragen. - supercat
@ mauro.stettler: Ich habe einen TCP-Stack auf "Bare Metal" geschrieben (schreibe den Code, um direkt mit einer Anzahl von Netzwerk-Interface-Chips zu sprechen). Für Hardware, die mit einer Verbindung mit einer 576-Byte-Grenze spricht, um längere Pakete aufzuteilen, ist einfach. Das Zusammensetzen von Paketen ist viel komplizierter, vor allem, da man Teile vieler verschiedener Pakete empfangen kann, bevor eines von ihnen vollständig empfangen wird. - supercat
Es besteht die Hoffnung, dass es nicht gespalten wird winzig Payloads (ungefähr 10 oder 20 Bytes sollten in Ordnung sein), weil es eine "garantierte maximale Größe" von jedem benötigt hüpfen für IP-Pakete auf IPv4: mindestens 68 Byte (einschließlich IP-Header und nicht untergeordnete Header). siehe die 1. Tabelle in en.wikipedia.org/wiki/Maximum_transmission_unit. Anders als die 576 Bytes mit minimaler Größe, die von den HOSTS benötigt werden (dh der Ursprung oder das Ende der Übertragung, nicht alle dazwischenliegenden Hops). Und vorsichtig: die Nutzlast ist noch niedriger (da die Header jeder Ebene etwas Platz brauchen). - Olivier Dulac


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

TCP:

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

Alle gesendeten Daten werden in der Reihenfolge empfangen, aber nicht notwendigerweise in den gleichen Abschnitten.

UDP:

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

Die Daten sind nicht notwendigerweise in der gleichen Reihenfolge und werden nicht unbedingt empfangen, sondern die Nachrichten bleiben in ihrer Gesamtheit erhalten.


14
2017-08-27 16:22





Zum Beispiel: wenn ich 20 Bytes mit TCP-Protokoll sende, kann ich 100% sicher sein, dass ich   wird genau 20 Bytes auf einmal empfangen, nicht 10 Bytes, dann noch 10   Bytes oder so?

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


5
2017-08-27 10:19





Es gibt eine gewisse Sicherheit, dass, wenn Sie 20 Bytes ganz am Anfang eines TCP-Streams senden, es nicht als zwei 10-Byte-Stücke ankommen wird. Dies liegt daran, dass der TCP-Stack keine so kleinen Segmente sendet: Es gibt eine minimale MTU-Größe. Wenn sich der Send irgendwo in der Mitte eines Streams befindet, sind alle Wetten deaktiviert. Es kann sein, dass Ihr Protokollstapel 10 Byte der Daten benötigt, um ein Segment zu füllen und es zu senden, und dann die nächsten zehn Bytes zu einem anderen Segment gehen.

Ihr Protokollstapel zerlegt Daten in Chunks und platziert sie in einer Warteschlange. Die Chunk-Größen basieren auf dem Pfad MTU. Wenn Sie eine Sendeoperation ausführen und weiterhin Daten in der Warteschlange stehen, sucht der Protokollstapel in der Regel nach dem Segment, das sich am Ende der Warteschlange befindet, um festzustellen, ob in diesem Segment Platz für das Hinzufügen weiterer Daten vorhanden ist. Der Raum könnte so klein wie ein Byte sein, so dass sogar ein Zwei-Byte-Sendevorgang in zwei Teile aufgeteilt werden könnte.

Auf der anderen Seite bedeutet die Segmentierung von Daten, dass es teilweise Lesevorgänge geben kann. Eine Empfangsoperation kann möglicherweise aufwachen und Daten erhalten, wenn nur ein Segment ankommt. In der weit verbreiteten Socket-API kann ein Empfangsaufruf 20 Bytes anfordern, aber er könnte mit 10 zurückkehren. Natürlich kann eine Pufferschicht darauf aufgebaut werden, die blockiert, bis 20 Bytes empfangen werden, oder die Verbindung bricht. In der POSIX-Welt kann diese API die Standard-I / O-Ströme sein: Sie können fdopen ein Socket-Deskriptor, um a zu erhalten FILE * streamen, und Sie können verwenden fread darauf einen Puffer zu füllen, so dass die vollständige Anfrage mit so vielen zufrieden ist read Anrufe wie es dauert.

UDP-Datagramme rahmen die Daten ein. Jeder Sendeanruf erzeugt ein Datagramm (aber siehe unten zum Thema Verkorken). Die andere Seite empfängt ein vollständiges Datagramm (und muss in der Socket-API einen Puffer angeben, der groß genug ist, um es zu halten, andernfalls wird das Datagramm abgeschnitten). Große Datagramme werden durch IP-Fragmentierung fragmentiert und transparent für Anwendungen neu zusammengesetzt. Wenn ein Fragment fehlt, ist das gesamte Datagramm verloren. Es gibt keine Möglichkeit, Teildaten in dieser Situation zu lesen.

Es existieren Erweiterungen für die Schnittstelle, die es mehreren Operationen erlauben, ein einzelnes Datagramm zu spezifizieren. Unter Linux kann ein Socket "verkorkt" werden (das Senden wird verhindert). Während es verkorkt ist, werden geschriebene Daten zu einer einzigen Einheit zusammengesetzt. Dann, wenn der Sockel "entkorkt" ist, kann ein einzelnes Datagramm gesendet werden.


1
2017-08-27 16:56



Das ist falsch: Wenn man einen Paquet mit einer Nutzlast von 10 oder 20 Bytes sendet, erzeugt dies 1 Paquet und (wie ich oben sagte), wenn man ipv4 verwendet, sollte es, auch wenn alle Header der anderen Protokollschichten hinzugefügt werden, passen innerhalb von 68 Bytes, wodurch sichergestellt wird, dass es alle Hops in einem Paket durchläuft. Tcp stack wird nicht (wie im ersten Absatz angedeutet) "warten, bis der mtu voll ist (dh mehrere Pakete hinzufügen, um ein richtiges zu erstellen)", um ein Paket zu senden! ... Dieses Verhalten würde viele Dinge kaputt machen ( selbst wenn diese "Fragmente" von & zum gleichen Paar von Hosts gesendet wurden) - Olivier Dulac
@OlivierDulac: Das ist falsch. TCP erzeugt normalerweise Pakete, wie es benötigt wird, und versucht, die Netzwerknutzung zu optimieren, so dass 20 Bytes in zwei verschiedenen Paketen enden können, wie von Kaz erklärt. Dies kann mit der Taste gesteuert werden TCP_NODELAY Socket-Option, die den Nagles-Algorithmus deaktiviert, der Bytes an Pakete sendet, wenn Ihre Anwendung schnellere TCP-Netzwerke benötigt. Außerdem sind 68 Bytes bei weitem nicht der De-facto-Standard für die Paketlänge: 1500 Bytes sind ein üblicherer Standardwert (dies variiert wirklich zwischen den Netzwerken). - jjmontes