9.11. Objekty socketů

Pythonovským rozhraním k transportní vrstvě je třída socket.socket. Socket představuje jeden koncový bod síťové konverzace – adresu, port a protokol (UDP nebo TCP), přes který konverzace probíhá. Kapitoly o ovládání hardwaru otevíraly instance UART ke komunikaci po vodiči; tato sekce otevírá instance socket ke komunikaci po síti. Podoba je stejná; podkladová služba je jen mnohem schopnější.

9.11.1. Vytvoření socketu

Socket popisují tři argumenty: jakou rodinu adres používá, jaký typ socketu nabízí a jaký protokol využívá. Výchozí hodnoty pokrývají případy, které používá zbytek této sekce:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)   # IPv4 TCP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)    # IPv4 UDP

Dvě konstanty, mezi kterými aplikace téměř v každém případě volí:

  • AF_INET – adresy IPv4 (číselná IP plus port). Nejběžnější volba. AF_INET6 je ekvivalent pro IPv6.

  • SOCK_STREAM – TCP spojení, spolehlivý proud bytů. SOCK_DGRAM je ekvivalent pro UDP.

Třetí argument (protokol) je ponechán na nule, což zvolí správnou výchozí hodnotu na základě prvních dvou. Úplný konstruktor je zdokumentován v socket — modul socket.

9.11.2. Adresy na socketu

Adresa socketu je n-tice (host, port)

("192.168.1.50", 80)
("0.0.0.0", 8000)

Host je IP adresa jako řetězec. Port je 16bitové celé číslo popsané na Porty.

Stojí za to znát hrstku speciálních řetězců hostitele:

  • "0.0.0.0" znamená „každé rozhraní IPv4 na tomto zařízení“. Server navázaný na tuto adresu přijímá spojení na jakékoli adrese, kterou kamera má.

  • "127.0.0.1" je localhost – provoz na ni nikdy neopustí zařízení. Užitečné pro testování.

  • "255.255.255.255" je adresa lokálního všesměrového vysílání (broadcast). UDP datagram odeslaný na ni jde každému zařízení na lokálním segmentu.

Doménová jména jako "example.com" nejsou platné řetězce hostitele v adrese socketu. Nejprve musí být přeložena na IP; Jména a DNS pokrývá volání getaddrinfo(), které to provádí.

9.11.3. Dvě role

Životní cyklus socketu závisí na tom, na které straně konverzace se nachází. Klientský socket volá connect() (nebo, u UDP, prostě sendto()), aby komunikoval se známým serverem. Serverový socket volá bind(), aby si zabral port, a poté buď listen() a accept() (u TCP), nebo recvfrom() (u UDP), aby přijímal příchozí provoz.

V obou případech se používá tentýž konstruktor socket; liší se pouze metody volané poté. Následující tři stránky procházejí praktické vzory:

9.11.4. Uzavření socketu

Každý socket drží malý kus stavu operačního systému (rezervaci portu, buffery, TCP stav spojení). Když s ním aplikace skončí, close() tento stav uvolní. Zapomenutý socket je pomalý únik, který se sčítá; ve smyčce, která otevírá spojení, vynechané close nakonec vyčerpá zásobu dostupných socketů kamery.

Nejčistším vzorem je příkaz with

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect(addr)
    s.send(b"GET / HTTP/1.0\r\n\r\n")
    ...
# socket is closed automatically here, even on error

Sockety implementují protokol kontextového manažeru popsaný v přehledu Pythonu, takže blok with zaručuje, že close() bude zavoláno bez ohledu na to, zda blok skončil normálně, nebo vyvoláním výjimky.

9.11.5. Reference modulu socket

Tato a následující stránky procházejí API ve formě výkladu. Úplnou referenci na úrovni argumentů pro každou metodu, každý příznak a každou konstantu, kterou modul zpřístupňuje, najdete v socket — modul socket. Reference je také místem, kde hledat méně běžné operace (volby socketu, členství v multicastové skupině, IPv6 scope ID), které tato sekce nepokrývá.