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_INET6je ekvivalent pro IPv6.SOCK_STREAM– TCP spojení, spolehlivý proud bytů.SOCK_DGRAMje 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:
UDP sokety – odesílání a příjem datagramů.
TCP sokety – TCP klient a server.
Sockety s asyncio – vše výše, ale uvnitř smyčky událostí
asyncio.
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á.