0%

Masken und Steuerframes

Nachrichten in Stücken

Jeder , den dein Codec gebaut hat, hat eine ganze Nachricht getragen, also war FIN in allen gesetzt, mit einer , die Kapitel 3, Lektion 3, gezeigt hat: encode_frame(OP_TEXT, "Hel", fin=False), ein Frame, der nicht final ist. Dieser Frame ist die Hälfte eines echten Beispiels. RFC 6455, Abschnitt 5.7, sendet “Hello” als zwei Frames:

01 03 48 65 6c
80 02 6c 6f

Der erste Frame ist 01: FIN nicht gesetzt, 1, Text, dann die Länge 3 und “Hel”. Der zweite ist 80: FIN gesetzt, Opcode 0, dann die Länge 2 und “lo”. Zusammen tragen sie eine Textnachricht, “Hello”. Das ist Fragmentierung, und diese Lektion liest sie, ohne Code dafür zu schreiben.

Die Regeln aus Abschnitt 5.4

Eine Nachricht, die auf mehrere Frames verteilt ist, ihre Fragmente, folgt drei Regeln:

  • Der erste Frame trägt den Opcode der Nachricht, 1 für Text oder 2 für binär, mit nicht gesetztem FIN.

  • Alle mittleren Frames tragen Opcode 0, Fortsetzung, mit nicht gesetztem FIN.

  • Der letzte Frame trägt Opcode 0 mit gesetztem FIN.

Opcode 0 sagt “dieser Frame setzt die Nachricht fort, die gerade läuft”; nur der erste Frame sagt, welche Art von Nachricht es ist. FIN markiert das Ende, also sammelt der Empfänger Payloads, bis ein Fortsetzungsframe mit gesetztem FIN ankommt, und fügt sie dann zusammen. Eine Nachricht in einem Frame ist einfach der Fall, in dem der erste Frame auch der letzte ist: Opcode 1 oder 2 mit gesetztem FIN, die einzige Art, die dein Codec bisher gesehen hat.

Dieser Block liest beide Frames mit den Bitoperationen aus Kapitel 3 und fügt ihre Payloads zusammen:

Try it

Welcher Frame beendet eine fragmentierte Nachricht?

Warum eine Nachricht aufteilen

Zwei Situationen bringen einen Sender dazu, eine Nachricht aufzuteilen. Die erste ist ein Sender, der zu Beginn nicht weiß, wie lang die Nachricht wird, zum Beispiel einer, der Daten sendet, während er sie erzeugt. Der Header eines Frames nennt die Payload-Länge vor der Payload, also sendet ein solcher Sender, was er hat, als Fragment und markiert das letzte Stück mit FIN, wenn er fertig ist.

Die zweite ist eine lange Nachricht, die nicht alles andere blockieren soll. Lektion 3 hat Steuerframes eine dritte Regel gegeben: Sie dürfen zwischen den Fragmenten einer Nachricht ankommen. Ein Sender mitten in einer großen Nachricht kann zwischen zwei Fragmenten anhalten, einen senden oder einen beantworten und weitermachen. Hier ist noch einmal das “Hello” des RFC, mit einem Ping, der “Hello” trägt, zwischen seinen beiden Teilen:

01 03 48 65 6c
89 05 48 65 6c 6c 6f
80 02 6c 6f

Der Empfänger verarbeitet den Ping für sich und kehrt dann zum Sammeln von “Hello” zurück. Daten-Frames dürfen sich nicht auf diese Weise abwechseln: Eine neue Text- oder Binärnachricht kann erst beginnen, wenn das letzte Fragment der aktuellen angekommen ist. Nur Steuerframes dürfen dazwischenfahren, und das ist ein Grund, warum ein Steuerframe selbst nie fragmentiert ist und bei 125 Bytes oder weniger bleibt.

Ein Ping kommt zwischen 01 03 48 65 6c und 80 02 6c 6f an. Ist das erlaubt?

Was der Lern-Codec tut

Fragmente zusammenzusetzen braucht einen Zustand, der über Frames hinweg besteht: den Opcode der laufenden Nachricht, die bisher gesammelten Payloads, eine Größengrenze für ihre Summe und die Regel, dass ein Steuerframe mittendrin ankommen darf. Der Lern-Codec tut das nicht. Das read_message, das du in Lektion 6 schreibst, lehnt jeden Frame mit nicht gesetztem FIN oder mit Opcode 0 ab und nennt für die Ablehnung einen .

Kein Close-Code bedeutet “dieser Endpunkt setzt fragmentierte Nachrichten nicht zusammen”. 1003, nicht unterstützte Daten, ist die am wenigsten falsche Wahl: Er sagt, dass der Endpunkt nicht annehmen kann, was angekommen ist. 1002, Protokollfehler, wäre falsch, weil er der Gegenseite die Schuld gibt, und eine Gegenseite, die eine Nachricht fragmentiert, verletzt keine Regel. Das ist eine Grenze des Lern-Codecs, gewählt, damit der Codec klein genug bleibt, um ihn in einem Kapitel zu schreiben, kein Fehler der Gegenseite. Ein konformer -Endpunkt muss fragmentierte Nachrichten akzeptieren.

Die Bibliothek websockets, die du ab Kapitel 6 verwendest, akzeptiert sie. In einem Lauf, der beim Schreiben dieses Kurses gemacht wurde, haben Frames, die mit dem Lern-Codec gebaut waren, “Hel”, einen Ping und “lo” über an einen Server der Bibliothek getragen. Der Server hat zuerst den Ping mit seinem Pong beantwortet und dann die ganze Nachricht, “Hello”, als eine Textnachricht zurückgeschickt. Kapitel 6, Lektion 5, kommt auf diesen Unterschied zwischen deinem Codec und der Bibliothek zurück.

Warum schließt der Lern-Codec mit 1003, wenn er ein Fragment sieht?

Der Lern-Codec ist also keine vollständige WebSocket-Implementierung, und er sagt das mit einem Code, statt auf verwirrende Weise zu scheitern. Die nächste Lektion, das Projekt des Kapitels, stellt jede Regel dieses Kapitels hinter eine , read_message, die einen Byte-Stream in Nachrichten und Steuerereignisse verwandelt und jeder Ablehnung ihren Close-Code gibt.