Trage clients en verloren verbindingen · oefening
Merk een dode peer op
Kijkers sturen nu vanuit hun eigen threads, en een kijker die sluit, verlaat het register binnen een halve seconde. Eén soort kijker blijft nog eeuwig: een die weg is zonder het te zeggen. Een telefoon loopt buiten bereik van de wifi, een laptopklep gaat dicht, een kabel wordt eruit getrokken. Er komt geen close-recv van de server geeft nooit b"" terug om te zeggen dat de andere kant sloot, omdat de machine die hem zou sluiten niet meer bereikbaar is. Een send naar die kijker lukt nog steeds, omdat die, zoals les 1 liet zien, alleen bytes in buffers zet. Een stille recv(timeout=0) vindt niets wachten, en dat is ook wat hij vindt bij een gezonde, stille kijker.
De enige manier om een dode peer van een stille te onderscheiden, is een vraag stellen die een antwoord nodig heeft.
Drie getallen
De bibliotheek stuurt die pings voor je, volgens het eigen schema van de verbinding, en drie van haar instellingen bepalen hoe lang een dode kijker kan blijven:
ping_interval: hoe vaak ze een ping stuurt;ping_timeout: hoe lang ze op de pong wacht;close_timeout: hoe lang ze, na het sturen van een close-frame, wacht tot de andere kant het sluiten afmaakt.
Als ping_timeout verstrijkt zonder pong, laat de bibliotheek de verbinding falen: ze stuurt een close-frame met code 1011 en de reden keepalive ping timeout, sluit daarna haar eigen kant van de verbinding, zodat de recv van de peer b"" zou teruggeven zodra die zo ver las, en wacht daarna tot close_timeout op het sluiten van de kant van de peer. Een dode peer sluit nooit, dus de bibliotheek wacht de hele close-time-out uit. Pas dan werpen de recv en send van de handler een

In woorden: één ping-interval na de laatste pong gaat er een ping uit; één ping-time-out later stuurt de bibliotheek close 1011 en sluit ze haar kant; één close-time-out later werpt de volgende blik van de handler ConnectionClosedError op, en verlaat de kijker het register.
De standaardwaarden zijn 20, 20 en 10 seconden. Die passen bij het internet, waar een traag mobiel netwerk seconden nodig kan hebben om te antwoorden. Ze maken een demonstratie op één machine erg traag, dus dit hoofdstuk geeft voor elk 1,0 seconde mee: PING_INTERVAL, PING_TIMEOUT en CLOSE_TIMEOUT bovenaan scoreboard_server.py. In lokale tests werd een stille client ongeveer 1,5 s na zijn laatste pong laten vallen met 0,5 s voor elke
Met ping_interval=1.0, ping_timeout=1.0 en de standaard close_timeout=10, hoe lang kan een dode kijker ongeveer geregistreerd blijven na zijn laatste pong?
Wat de handler ziet
Als de bibliotheek het opgeeft, werpt de volgende recv of send van de handler ConnectionClosedError op. Lees hem zoals je in hoofdstuk 6 leerde: exc.sent is het close-frame dat deze kant stuurde, met exc.sent.code 1011 en exc.sent.reason keepalive ping timeout, en exc.rcvd is None, omdat er geen close-frame terugkwam. Je describe_close uit hoofdstuk 6 leest rcvd, dus op de server zou hij 1006 melden: er kwam geen close-frame aan.
Er valt niets nieuws te schrijven in viewer_handler. Zijn volgende stille controle roept recv(timeout=0) aan, die de ConnectionClosedError opwerpt; except ConnectionClosed: pass beëindigt de finally-blok verwijdert de kijker. De stille controle uit les 3 is hoe een dode kijker wordt opgemerkt.
De keepalive van je server geeft een kijker op. Welke code bevat sent van de exception?
Een regel in het log
Als de close-time-out verloopt, schrijft de bibliotheek ook een blok naar standard error: een eerste regel, keepalive ping failed, en een
keepalive ping failed
TimeoutError: timed out while closing connection
websockets.exceptions.ConnectionClosedError: sent 1011 (internal error) keepalive ping timeout; no close frame received
Dat is de bibliotheek die een dode peer meldt, geen fout in je code. De Run van deze les gebruikt een stand-in-kijker, dus het blok verschijnt hier niet. In les 6 ontmoet pl_ws.py een echte stille client en drukt het het blok af als één regel.
Configureer de server op één plek
open_server(board, *, serve=serve) maakt de bibliotheekserver voor een bord, met deze waarden, en geeft hem terug zonder hem te starten. Zijn body is één aanroep van serve, met de handler uit make_handler(board), de host 127.0.0.1, 127.0.0.1 houdt de server op deze machine. De serve is een keyword-only argument met de serve van de bibliotheek als standaardwaarde, hetzelfde soort naad dat run_echo in hoofdstuk 6 had: een aanroeper kan een andere open_server om zou hebben gevraagd. pl_ws.py doet precies dat, om je drie waarden te leren voordat het zijn server bouwt, en de sectie van les 4 in Run doet het ook. Wie open_server aanroept, draait de server met serve_forever en stopt hem met shutdown.
Je opdracht
Schrijf in scoreboard_server.py open_server(board, *, serve=serve): roep serve aan met make_handler(board), "127.0.0.1", 0 en de drie keyword-argumenten, en geef terug wat die teruggeeft.
Uitvoeren
Klik op Run. De sectie van les 4 roept je open_server aan met een eigen serve die de keyword-argumenten vastlegt, drukt ze af, en geeft daarna viewer_handler een stand-in-kijker D waarvan de stille controle de exception opwerpt die de bibliotheek opwerpt na een gemiste pong, alsof
Lesson 4: a viewer that stopped answering pings
ping_interval = 1.0
ping_timeout = 1.0
close_timeout = 1.0
after the library gave up on D, the registry holds: []
Klik daarna op Submit.
Les 5 steekt over naar de andere kant van de verbinding: wat het programma van een kijker moet doen als zijn server hem laat vallen.
Opdracht
Schrijf in scoreboard_server.py open_server(board, *, serve=serve). Roep de serve één keer aan, met make_handler(board) als handler, "127.0.0.1" als host en 0 als ping_interval=PING_INTERVAL, ping_timeout=PING_TIMEOUT en close_timeout=CLOSE_TIMEOUT. Geef terug wat serve teruggeeft.
Roep serve_forever of shutdown niet aan, en gebruik geen with-blok: dat doet wie de server draait.
Klik op Run: de sectie van les 4 drukt ping_interval = 1.0, ping_timeout = 1.0, close_timeout = 1.0 en after the library gave up on D, the registry holds: [] af. Standard error blijft leeg: de stand-in-kijker D werpt de keepalive ping failed.
Klik daarna op Submit. De controle roept open_server aan met een stand-in-serve die zijn argumenten vastlegt en weigert gestart te worden; ze vervangt eerst de eigen serve van de make_handler(board) (ze roept die handler aan met een stand-in-kijker op /watch en controleert dat de kijker dat bord binnenkomt), "127.0.0.1" en poort 0, en ping_interval, ping_timeout en close_timeout elk meegegeven als een getal boven 0 en hoogstens 2.0. Daarna geeft ze viewer_handler een kijker waarvan de tweede stille controle de ConnectionClosedError opwerpt die de bibliotheek opwerpt na een gemiste