Frames, Byte für Byte · Übung
Drei Arten, die Länge anzugeben
Sieben Bits fassen die Zahlen 0 bis 127, und eine Payload kann weit länger sein. RFC 6455 löst das, ohne jeden Header größer zu machen. Längen von 0 bis 125 kommen direkt in das 7-Bit-Feld, wie in Lektion 3. Die beiden übrigen
Hier sind die Header an den Grenzen, jedes Byte vor der Payload. Die ersten vier sind Text-
payload bytes header
0 81 00
125 81 7d
126 81 7e 00 7e
127 81 7e 00 7f
256 82 7e 01 00
65535 82 7e ff ff
65536 82 7f 00 00 00 00 00 01 00 00
Lies die Zeile für 256 Bytes: 7e ist 126, die Markierung, und 01 00 ist die Länge in zwei Bytes, 1 mal 256 plus 0. Die Zeile für 65536 Bytes hat die Markierung 127, 7f, und dann acht Bytes, die 65536 enthalten, also 1 mal 256 mal 256. Der RFC selbst verwendet diese beiden Zeilen als seine Beispiele für die längeren Formen.
Wieder struct
Zwei Bytes und acht Bytes sind Aufgaben für struct, das du in Networks with Python, Kapitel 8, mit dem Format "!I" verwendet hast, einer vorzeichenlosen 4-Byte-Ganzzahl in "!H" ist eine vorzeichenlose Ganzzahl in 2 Bytes, 0 bis 65535, und "!Q" eine in 8 Bytes. Das ! bedeutet weiterhin Netzwerk-Byte-Reihenfolge, Big-Endian, das höchstwertige Byte zuerst, und der RFC verlangt genau diese Reihenfolge. struct.unpack gibt weiterhin ein [0]:
Was gibt das aus?
import struct
print((bytes([0x81, 126]) + struct.pack("!H", 127)).hex(" "))
Immer die kürzeste Form
Nichts in den Bytes hindert einen Sender daran, die Länge 5 als Markierung 126 und dann 00 05 zu schreiben. RFC 6455 schließt das aus: Abschnitt 5.2 sagt, dass die minimale Anzahl von Bytes verwendet werden muss, um die Länge zu kodieren. Also hat jede Länge genau einen Header, und ein Leser lehnt jeden anderen ab. Diese drei werden abgelehnt:
81 7e 00 7d a 16-bit length of 125, which fits in 7 bits
82 7f 00 00 00 00 00 00 ff ff a 64-bit length of 65535, which fits in 16 bits
82 7f 80 00 00 00 00 00 00 00 a 64-bit length with its top bit set
Die dritte Regel ist eine eigene. Der RFC verlangt, dass das oberste Bit der 8-Byte-Länge 0 ist, also ist die größte Länge, die ein Frame ankündigen kann, 2 hoch 63 minus 1. Das ist immer noch weit mehr, als irgendein Server akzeptieren sollte, und ein Leser, der es glaubte, würde auf eine Payload warten oder versuchen, eine Payload zu halten, die kein Programm verarbeiten könnte. Lektion 5 fügt aus diesem Grund eine Größengrenze hinzu.
Ein Frame gibt die Länge 126 an und dann 00 7d. Was sollte ein Decoder tun?
Die Funktion read_length
Kodieren ist eine read_length(length, read_exact) zwei parse_header_bytes und eine Funktion, mit der weitere Bytes gelesen werden.
read_exact(n) ist die Funktion, die du in Networks with Python, Kapitel 6, Lektion 3, als read_exact(reader, n) geschrieben hast: Sie gibt genau n Bytes zurück, egal wie die Verbindung sie liefert, behält zusätzliche Bytes in einem Puffer und löst ConnectionError aus, wenn die Gegenseite vorher schließt. Hier kommt sie als read_length nie wissen, woher die Bytes kommen. Eine echte Verbindung, ein Test und frames_demo.py können ihr jeweils ihr eigenes read_exact übergeben. Zum Beispiel mit einem Stellvertreter aus der Datei fakes.py des Kapitels, der die Bytes 01 00 enthält:
read_exact = fakes.reader_over([bytes([1, 0])])
# reads 2 bytes and returns 256
ws_frames.read_length(126, read_exact)
Bei einer Länge von 125 oder weniger liest read_length nichts und gibt die Länge selbst zurück. Bei 126 liest sie 2 Bytes und entpackt sie mit "!H"; bei 127 8 Bytes mit "!Q". Dann prüft sie die Regeln oben, bevor sie zurückgibt.
Deine Aufgabe
In ws_frames.py:
Schreibe
length_field(n). Gib für 0 bis 125bytes([n])zurück; für 126 bis 65535 das Byte 126, gefolgt vonstruct.pack("!H", n); und darüber das Byte 127, gefolgt vonstruct.pack("!Q", n).Schreibe
read_length(length, read_exact). Giblengthzurück, wenn es 125 oder weniger ist, ohne zu lesen. Lies nach 126 2 Bytes und löseaus, wenn die Zahl 125 oder weniger ist. Lies nach 127 8 Bytes und löse ValueErroraus, wenn das oberste Bit gesetzt ist (die Zahl über0x7FFFFFFFFFFFFFFFliegt) oder wenn die Zahl 65535 oder weniger ist.Ändere
encode_frame: Entferne die Grenze von 125 Bytes und baue die Längenbytes mitlength_field(len(payload)). Alles andere bleibt so, wie Lektion 3 es geschrieben hat.
Klicke auf Run. Der Abschnitt zu Lektion 4 gibt keine Ablehnung mehr aus. Er zeigt die ersten zehn Bytes eines 65536 Byte langen binären Frames, den Header des RFC:
Lesson 4: the start of a 65536-byte frame
82 7f 00 00 00 00 00 01 00 00
Klicke dann auf Submit. Die Prüfung vergleicht length_field an jeder Grenze und bei Längen, die du nicht gesehen hast, mit Bytes, die mit struct gebaut sind, prüft die 256-Byte- und 65536-Byte-Header des RFC aus encode_frame zusammen mit den kleinen Frames aus Lektion 3 und übergibt read_length ein Stellvertreter-read_exact, das aufzeichnet, wie viele Bytes angefordert wurden. Mehr anzufordern, als die Form braucht, schlägt fehl, und einen der drei abgelehnten Header zu akzeptieren ebenso.
Der Codec kann jetzt jede Länge schreiben und lesen. Die nächste Lektion fügt die lesenden Teile zu decode_frame zusammen, das einen ganzen Frame aus einem Stream liest.
Aufgabe
In ws_frames.py:
Schreibe
length_field(n): die Längenbytes für einenBytes lange Payload in der kürzesten Form.bytes([n])für 0 bis 125; das Byte 126 und dannstruct.pack("!H", n)für 126 bis 65535; das Byte 127 und dannstruct.pack("!Q", n)darüber.Schreibe
read_length(length, read_exact): Giblengthselbst zurück, wenn es 125 oder weniger ist, und lies nichts. Wenn es 126 ist, lies 2 Bytes mitread_exact(2)und entpacke sie mit"!H"; wenn es 127 ist, lies 8 Bytes und entpacke sie mit"!Q". Löseaus bei einer Länge, die eine kürzere Form hätte verwenden sollen (125 oder weniger nach 126, 65535 oder weniger nach 127), und bei einer 8-Byte-Länge mit gesetztem oberstem Bit. Ändere
encode_frameso, dass es keine Grenze von 125 Bytes hat und seine Längenbytes mitlength_field(len(payload))baut.
Klicke auf Run: Der Abschnitt zu Lektion 4 sollte 82 7f 00 00 00 00 00 01 00 00 ausgeben. Klicke dann auf Submit. Die Prüfung vergleicht length_field mit Bytes, die sie mit struct baut, an jeder Grenze und bei Längen, die du nicht gesehen hast; prüft die 256-Byte- und 65536-Byte-Header des RFC und die kleinen encode_frame; und gibt read_length ein Stellvertreter-read_exact, das jede angeforderte Anzahl aufzeichnet. read_length darf nichts, genau 2 oder genau 8 Bytes anfordern und muss eine 16-Bit-125 oder -0, eine 64-Bit-65535 und eine 64-Bit-Länge mit gesetztem oberstem Bit ablehnen. int.to_bytes und int.from_bytes mit "big" sind statt struct in Ordnung.