9.11. Objetos socket¶
A interface Python para a camada de transporte é a classe socket.socket. Um socket representa um ponto final de uma conversa de rede – um endereço, uma porta e o protocolo (UDP ou TCP) sobre o qual a conversa ocorre. Os capítulos de controle de hardware abriam instâncias de UART para conversar por um fio; esta seção abre instâncias de socket para conversar pela rede. A forma é a mesma; o serviço subjacente é apenas muito mais capaz.
9.11.1. Criando um socket¶
Três argumentos descrevem um socket: qual família de endereços ele fala, qual tipo de socket ele oferece e qual protocolo ele usa. Os padrões cobrem os casos que o restante desta seção utiliza:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # IPv4 TCP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # IPv4 UDP
As duas constantes entre as quais a aplicação escolhe em quase todos os casos:
AF_INET– endereços IPv4 (um IP numérico mais uma porta). A escolha mais comum.AF_INET6é o equivalente IPv6.SOCK_STREAM– uma conexão TCP, o fluxo de bytes confiável.SOCK_DGRAMé o equivalente UDP.
O terceiro argumento (o protocolo) fica em zero, o que escolhe o padrão correto com base nos dois primeiros. O construtor completo está documentado em socket — módulo socket.
9.11.2. Endereços em um socket¶
Um endereço de socket é uma tupla de (host, port)
("192.168.1.50", 80)
("0.0.0.0", 8000)
O host é o endereço IP como uma string. A porta é o inteiro de 16 bits abordado em Portas.
Vale conhecer um punhado de strings de host especiais:
"0.0.0.0"significa “toda interface IPv4 neste dispositivo”. Um servidor vinculado a este endereço aceita conexões em qualquer endereço que a câmera possua."127.0.0.1"é o localhost – o tráfego para ele nunca sai do dispositivo. Útil para testes."255.255.255.255"é o endereço de broadcast local. Um datagrama UDP enviado a ele vai para todo dispositivo no segmento local.
Nomes de domínio como "example.com" não são strings de host válidas em um endereço de socket. Eles precisam ser resolvidos para um IP primeiro; Nomes e DNS aborda a chamada getaddrinfo() que faz isso.
9.11.3. Os dois papéis¶
O ciclo de vida de um socket depende de qual lado da conversa ele está. Um socket cliente chama connect() (ou, no caso do UDP, apenas sendto()) para conversar com um servidor conhecido. Um socket servidor chama bind() para reivindicar uma porta, e então listen() e accept() (para TCP) ou recvfrom() (para UDP) para receber o tráfego de entrada.
O mesmo construtor de socket é usado em ambos os casos; apenas os métodos chamados em seguida diferem. As próximas três páginas percorrem os padrões práticos:
Sockets UDP – enviar e receber datagramas.
Sockets TCP – cliente e servidor TCP.
Sockets com asyncio – tudo o que está acima, mas dentro de um loop de eventos
asyncio.
9.11.4. Fechando um socket¶
Todo socket mantém um pequeno fragmento de estado do sistema operacional (uma reserva de porta, buffers, o estado TCP da conexão). Quando a aplicação termina de usá-lo, close() libera esse estado. Um socket esquecido é um vazamento lento que se acumula; em um loop que abre conexões, esquecer um close acabará esgotando o pool de sockets disponíveis da câmera.
O padrão mais limpo é a instrução 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
Os sockets implementam o protocolo de gerenciador de contexto abordado na visão geral do Python, então o bloco with garante que close() seja chamado independentemente de o bloco ter saído normalmente ou ao lançar uma exceção.
9.11.5. A referência do módulo socket¶
Esta e as próximas páginas percorrem a API em forma narrativa. Para a referência completa, no nível dos argumentos, de cada método, cada flag e cada constante que o módulo expõe, consulte socket — módulo socket. A referência também é o lugar para procurar as operações menos comuns (opções de socket, participação em grupos multicast, IDs de escopo IPv6) que esta seção não aborda.