0%

Die Bibliothek websockets, ohne asyncio

Was die Bibliothek für dich getan hat

Dein Echo-Handler ist eine aus ein paar Zeilen, und dein Client besteht aus ein paar mehr. Die Kapitel 2 bis 5 haben 618 Zeilen in drei Dateien gebraucht, um dieselbe Arbeit zu erledigen. Nichts von dieser Arbeit ist verschwunden: Jeder bekommt weiterhin einen Header, jeder Client-Frame ist weiterhin maskiert, jeder Close wird weiterhin beantwortet. Die Bibliothek erledigt es jetzt. Diese Lektion legt beides nebeneinander, damit jede Sache, die die Bibliothek tut, einen Namen hat, den du kennst, und sieht sich dann an, was die Bibliothek tut, das dein Code nie getan hat.

Was die Bibliothek übernommen hat

Auf der LeitungWo du es geschrieben hastWo die Bibliothek es erledigt
Die Hälfte des Servers beim : die Anfrage lesen, sie prüfen, mit 101 und dem Accept- antwortenserve_handshake, check_upgrade, accept_value (Kapitel 2)in serve, bevor dein Handler aufgerufen wird
Die Hälfte des Clients: ein neuer Schlüssel, die Anfrage, die Prüfung des Accept-Wertsmake_client_key, build_upgrade_request, check_accept_response, client_handshake (Kapitel 2)in connect, bevor es zurückkehrt
Frames: der Header, die drei Längenformen, für Textencode_frame, decode_frame, read_message (Kapitel 3 und 4)in send und recv
Maskieren und das Ablehnen eines Frames, der für seine Richtung falsch maskiert istapply_mask, client_frame und der Schlüsselwortparameter require_mask von decode_frame (Kapitel 4 und 5)in send und recv, je nach Rolle
Einen mit einem Pong mit derselben Payload beantwortenreply_to_ping (Kapitel 4), server_reply (Kapitel 5)sobald jeder Ping ankommt
Der Schließ-Handshakeclose_frame, wait_for_close (Kapitel 5)in close und am Ende des with-Blocks eines Clients
Die Verbindung mit 1002, 1007 oder 1009 scheitern lassenfailure_frame (Kapitel 5)sobald der fehlerhafte Frame ankommt, mit denselben Codes

Die letzte Zeile verdient einen genaueren Blick, weil die beiden hier hätten voneinander abweichen können. In lokalen Tests gegen den Protokollcode der Bibliothek wurde ein unmaskierter Frame an einen Bibliotheks-Server mit Close 1002 und dem Grund incorrect masking beantwortet, ein Close-Grund, der kein gültiges UTF-8 war, mit 1007 und ein Frame über der Größengrenze mit 1009. Das sind die Codes, die dein failure_frame für dieselben Fehler sendet. Auch der Schließ-Handshake stimmt Byte für Byte überein: Wenn die Bibliothek einen Close beantwortet, sendet sie die Payload, die sie empfangen hat, unverändert zurück, wie es dein close_frame tut. Ein Kommentar in ihrem Quelltext erklärt, warum: Einen leeren Close neu aufzubauen würde scheitern, weil ein leerer Close als 1005 gemeldet wird, ein Code, der nicht gesendet werden darf.

Was sie tut, das deiner nicht getan hat

Der Lern-Codec war ehrlich, was seine Grenzen angeht, und die Bibliothek füllt jede davon aus.

Fragmente. Dein Codec hat eine fragmentierte Nachricht mit 1003 abgelehnt. Ein konformer Endpunkt muss Fragmente akzeptieren, und die Bibliothek tut das. In einem lokalen Test hat der Codec aus Kapitel 5 einem Bibliotheks-Server Hel als unfertiges Text-Fragment gesendet, dann einen Ping, dann lo als letztes Fragment. Der Server hat den Ping mit einem Pong beantwortet, und sein Handler hat Hello am Stück empfangen und als Echo zurückgesendet.

Ein Client sendet Hel und lo als zwei Fragmente an einen Bibliotheks-Server. Was gibt das recv des Handlers zurück?

Kompression. Standardmäßig bietet die Bibliothek während des Handshakes permessage-deflate an, eine Erweiterung, die jede Nachricht komprimiert (compression="deflate"). Komprimierte Frames setzen RSV1, ein Bit, das dein Codec ablehnt. Das war nur sicher, weil dein Server aus Kapitel 5 der Erweiterung nie zugestimmt hat, also hat der Interop-Lauf in Lektion 1 keine verwendet. Dieser Kurs lässt Kompression weg.

. Alle 20 Sekunden sendet die Bibliothek einen Ping (ping_interval=20), und wenn der Pong nicht innerhalb von 20 Sekunden ankommt (ping_timeout=20), schließt sie die Verbindung. Dein Client hat zu Beginn eines Gesprächs einen Ping gesendet, nie einen nach Zeitplan, also blieb eine Gegenseite, die kommentarlos verschwunden ist, unbemerkt, bis ein Lesevorgang in ein Timeout lief. Darum geht es in Kapitel 8.

Eine Standard-Größengrenze. Die Bibliothek lehnt eine Nachricht über 1 ab, max_size=1048576 Bytes, und schließt die Verbindung mit 1009. Das MAX_SIZE deines Codecs war 1.000.000 Bytes, also liegen die beiden Grenzen nahe beieinander, sind aber nicht gleich.

Diese Standardwerte gehören zu Version 17.4, der, die du festgelegt hast. Eine andere Version kann sie ändern, und das ist ein weiterer Grund für die Festlegung.

Mit Standardeinstellungen sendet ein Client eine Nachricht von 2.000.000 Bytes an einen Bibliotheks-Server. Was passiert?

Eine Bequemlichkeit, die dieser Kurs auslässt

Eine Verbindung kann auch mit einer for-Schleife gelesen werden:

for message in connection:
    connection.send(message)

Die Schleife liest eine Nachricht pro Durchlauf und endet still, wenn die Verbindung normal schließt. Sie liest sich gut, und sie hat kein Timeout: Ein Client, der sich verbindet und nichts sagt, hält die Schleife und ihren Thread fest, so lange die Verbindung offen bleibt. Jeder Lesevorgang in diesem Kurs ist begrenzt, also durchlaufen Handler stattdessen recv(timeout=...) in einer Schleife und fangen ConnectionClosed ab.

Warum schreibt dieser Kurs nicht for message in connection:?

Alles, was du brauchst, um den Echo-Dienst aus Kapitel 5 neu zu bauen, steht jetzt in echo_library.py. Das Projekt fügt es zu einem Programm mit einer zusammen.