9.11. Oggetti socket¶
L’interfaccia Python verso il livello di trasporto è la classe socket.socket. Un socket rappresenta un’estremità di una conversazione di rete – un indirizzo, una porta e il protocollo (UDP o TCP) su cui la conversazione si svolge. I capitoli sul controllo dell’hardware aprivano istanze UART per comunicare su un filo; questa sezione apre istanze socket per comunicare sulla rete. La forma è la stessa; il servizio sottostante è solo molto più capace.
9.11.1. Creare un socket¶
Tre argomenti descrivono un socket: quale famiglia di indirizzi parla, quale tipo di socket offre e quale protocollo usa. I valori predefiniti coprono i casi usati dal resto di questa sezione:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # IPv4 TCP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # IPv4 UDP
Le due costanti tra cui l’applicazione sceglie in quasi tutti i casi:
AF_INET– indirizzi IPv4 (un IP numerico più una porta). La scelta più comune.AF_INET6è l’equivalente IPv6.SOCK_STREAM– una connessione TCP, il flusso di byte affidabile.SOCK_DGRAMè l’equivalente UDP.
Il terzo argomento (il protocollo) è lasciato a zero, il che seleziona il valore predefinito corretto in base ai primi due. Il costruttore completo è documentato in socket — modulo socket.
9.11.2. Indirizzi su un socket¶
Un indirizzo di socket è una tupla (host, port)
("192.168.1.50", 80)
("0.0.0.0", 8000)
L’host è l’indirizzo IP come stringa. La porta è l’intero a 16 bit trattato in Porte.
Vale la pena conoscere una manciata di stringhe host speciali:
"0.0.0.0"significa «ogni interfaccia IPv4 su questo dispositivo». Un server associato a questo indirizzo accetta connessioni su qualsiasi indirizzo posseduto dalla camera."127.0.0.1"è localhost – il traffico verso di esso non lascia mai il dispositivo. Utile per i test."255.255.255.255"è l’indirizzo di broadcast locale. Un datagramma UDP inviato a esso raggiunge ogni dispositivo sul segmento locale.
I nomi di dominio come "example.com" non sono stringhe host valide in un indirizzo di socket. Devono prima essere risolti in un IP; Nomi e DNS tratta la chiamata getaddrinfo() che fa questo.
9.11.3. I due ruoli¶
Il ciclo di vita di un socket dipende da quale lato della conversazione si trova. Un socket client chiama connect() (o, per UDP, semplicemente sendto()) per comunicare con un server noto. Un socket server chiama bind() per rivendicare una porta, quindi listen() e accept() (per TCP) oppure recvfrom() (per UDP) per ricevere il traffico in entrata.
In entrambi i casi viene usato lo stesso costruttore socket; differiscono solo i metodi chiamati successivamente. Le tre pagine seguenti illustrano i pattern pratici:
Socket UDP – inviare e ricevere datagrammi.
Socket TCP – client e server TCP.
Socket con asyncio – tutto quanto sopra, ma all’interno di un loop di eventi
asyncio.
9.11.4. Chiudere un socket¶
Ogni socket detiene una piccola porzione di stato del sistema operativo (una prenotazione di porta, buffer, lo stato TCP della connessione). Quando l’applicazione ha finito di usarlo, close() rilascia quello stato. Un socket dimenticato è una lenta perdita che si accumula; in un loop che apre connessioni, la mancanza di un close finirà per esaurire il pool di socket disponibili della camera.
Il pattern più pulito è l’istruzione 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
I socket implementano il protocollo del gestore di contesto trattato nella panoramica di Python, quindi il blocco with garantisce che close() venga chiamato indipendentemente dal fatto che il blocco sia terminato normalmente o sollevando un’eccezione.
9.11.5. Il riferimento di socket¶
Questa pagina e le successive illustrano l’API in forma narrativa. Per il riferimento completo a livello di argomenti di ogni metodo, ogni flag e ogni costante esposti dal modulo, vedere socket — modulo socket. Il riferimento è anche il luogo in cui cercare le operazioni meno comuni (opzioni dei socket, appartenenza a gruppi multicast, ID di scope IPv6) che questa sezione non tratta.