De bibliotheek websockets, zonder asyncio · oefening
Verbinding maken als client
Je bibliotheekserver heeft tot nu toe alleen met de zelfgebouwde client uit hoofdstuk 5 gepraat. Deze les schrijft de andere kant met de bibliotheek, echo_once(url, texts, *, connect=connect), en richt die ene client daarna op beide servers: die van jou uit les 2 en de server uit hoofdstuk 5.
Een URL in plaats van een adres
De client van de bibliotheek neemt een ws://127.0.0.1:50123/echo zoals ws betekent wss zou 127.0.0.1 en 50123 zijn de host en de poort waarmee verbinding wordt gemaakt, en /echo is het pad.
Uit die delen bouwt de bibliotheek het upgradeverzoek dat je in hoofdstuk 2 met de hand bouwde met build_upgrade_request: een GET-verzoekregel met het pad als doel, een Host-header, een nieuwe Sec-WebSocket-Key en Sec-WebSocket-Version: 13. Als de 101 aankomt, controleert ze de Sec-WebSocket-Accept tegen haar sleutel, het werk dat je check_accept_response deed.
Welke verzoekregel stuurt de bibliotheek voor ws://127.0.0.1:50123/echo?
Aan elke kant begrensd
connect, uit websockets.sync.client, opent de TCP-verbinding, voert de send, recv en close die je handler gebruikte. Een client wacht op drie plekken, en deze cursus begrenst elk ervan met WAIT, 2 seconden:
open_timeout=WAITbegrenst de handshake. De eigen standaardwaarde van de bibliotheek is 10 seconden.recv(timeout=WAIT)begrenst elke echo, zoals in je handler.close_timeout=WAITbegrenst de sluithandshake. De standaardwaarde daarvan is ook 10 seconden.
Een grens maakt van een wachttijd een connect TimeoutError op met de melding timed out while waiting for handshake response zodra open_timeout verstreken is. In een lokale test met open_timeout=0.5 tegen een listener die nooit antwoordde, duurde dat ongeveer een halve seconde.
Op elke connect komt nog één proxy=None. Standaard leest de bibliotheek proxy-instellingen uit de omgeving, zoals de HTTP_PROXY, en volgt die zelfs voor 127.0.0.1. In een lokale test met HTTP_PROXY ingesteld op een poort waar niets luisterde, ging een verbinding die voor een proxy=None bereikte dezelfde verbinding de server. Of een machine zo’n variabele instelt, is niet iets waar een loopback-programma van mag afhangen, dus elke connect in deze cursus geeft proxy=None mee.
Gebruik connect(...) altijd in een with-statement. De versie die je in les 1 vastpinde, geeft een DeprecationWarning als connect op een andere manier wordt aangeroepen.
Waarom geeft elke connect in deze cursus proxy=None mee?
Het blok verlaten
Het gesprek van een client staat binnen het with-blok:
with connect(url, open_timeout=WAIT, close_timeout=WAIT, proxy=None) as connection:
connection.send("hello")
Als het blok eindigt, op welk pad ook, stuurt de client een close-close_timeout, op de beantwoordende close van de server en op het sluiten van de TCP-verbinding door de server. Dat is de sluithandshake die je in hoofdstuk 5 schreef met close_frame en wait_for_close, nu voor je uitgevoerd.
Wat gebeurt er als het blok with connect(...) eindigt?
Je opdracht
Schrijf echo_once(url, texts, *, connect=connect) in echo_library.py. Open de verbinding met connect(url, open_timeout=WAIT, close_timeout=WAIT, proxy=None) in een with-statement. Stuur voor elke tekst die tekst en lees de echo ervan met connection.recv(timeout=WAIT), en voeg de echo toe aan een connect=connect is dezelfde soort naad als serve=serve: Submit geeft een stand-in mee.
Voordat je op Run drukt
Run drukt deze keer twee van de blokken uit les 2 af, elk beginnend met connection handler failed, één voor elk gesprek dat je handler uit les 2 bedient. Het eerste komt uit de sectie van les 2, zoals eerder. Het tweede komt uit de eerste sectie van les 3: je client verlaat zijn with-blok terwijl je handler in recv wacht, dus de handler loopt weer tegen een close aan, deze keer zonder reden. Dat blok eindigt met:
websockets.exceptions.ConnectionClosedOK: received 1000 (OK); then sent 1000 (OK)
Beide zijn te verwachten, Submit accepteert ze nog steeds, en les 4 haalt ze weg.
Druk op Run. Na de sectie van les 2 drukte een afgewerkte versie, gedraaid op de site, af:
Lesson 3: your library client, your library server
['hello', 'café ✓', 'third message']
Lesson 3: your library client, the Chapter 5 server
{'client': ['hello', 'café ✓', 'third message'], 'Chapter 5 server': [{'messages': 3, 'code': 1000}]}
De eerste sectie is de bibliotheek aan beide kanten. De tweede is opnieuw de interopcontrole van les 1, deze keer met je eigen client: de server uit hoofdstuk 5 meldt drie berichten en een close met 1000. Druk daarna op Submit.
Beide gesprekken eindigen met een
Opdracht
Schrijf echo_once(url, texts, *, connect=connect) in echo_library.py:
open de verbinding met
connect(url, open_timeout=WAIT, close_timeout=WAIT, proxy=None)in eenwith-statement;stuur elke tekst met
connection.senden lees de echo ervan metconnection.recv(timeout=WAIT), en voeg de echo toe aan een; geef de lijst terug.
Druk op Run: de twee secties van les 3 moeten ['hello', 'café ✓', 'third message'] afdrukken en dezelfde echo’s met het verslag van de server uit hoofdstuk 5, [{'messages': 3, 'code': 1000}]. Er verschijnen twee blokken connection handler failed op standaardfout, zoals de les beschrijft.
Druk daarna op Submit. De controle opent nooit een echo_once een stand-in-connect en noteert hoe die wordt aangeroepen: de url ongewijzigd doorgegeven, open_timeout en close_timeout elk ingesteld en hooguit 2 seconden, en proxy=None. De stand-in-verbindingen beantwoorden teksten die je nog niet hebt gezien, en een ervan beantwoordt elke tekst in hoofdletters, dus de lijst die je teruggeeft, moet bevatten wat recv teruggaf, op volgorde. Elke recv heeft een time-out van hooguit 2 seconden nodig, één recv per tekst, en de verbinding moet in een with-statement worden gebruikt. Alle teksten sturen voordat je alle echo’s leest, is prima.