9.11. Objetos socket

La interfaz de Python con la capa de transporte es la clase socket.socket. Un socket representa un extremo de una conversación de red – una dirección, un puerto y el protocolo (UDP o TCP) sobre el que se ejecuta la conversación. Los capítulos sobre el control del hardware abrían instancias de UART para comunicarse por un cable; esta sección abre instancias de socket para comunicarse por la red. La forma es la misma; el servicio subyacente es simplemente mucho más capaz.

9.11.1. Crear un socket

Tres argumentos describen un socket: qué familia de direcciones habla, qué tipo de socket ofrece y qué protocolo usa. Los valores predeterminados cubren los casos que usa el resto de esta sección:

import socket

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

Las dos constantes entre las que elige la aplicación en casi todos los casos:

  • AF_INET – direcciones IPv4 (una IP numérica más un puerto). La opción más común. AF_INET6 es el equivalente para IPv6.

  • SOCK_STREAM – una conexión TCP, el flujo de bytes fiable. SOCK_DGRAM es el equivalente para UDP.

El tercer argumento (el protocolo) se deja en cero, lo que elige el valor predeterminado correcto en función de los dos primeros. El constructor completo está documentado en socket — módulo socket.

9.11.2. Direcciones en un socket

Una dirección de socket es una tupla (host, port):

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

El host es la dirección IP como una cadena. El puerto es el entero de 16 bits que se trató en Puertos.

Conviene conocer un puñado de cadenas de host especiales:

  • "0.0.0.0" significa «todas las interfaces IPv4 de este dispositivo». Un servidor vinculado a esta dirección acepta conexiones en cualquier dirección que tenga la cámara.

  • "127.0.0.1" es localhost – el tráfico hacia ella nunca sale del dispositivo. Útil para pruebas.

  • "255.255.255.255" es la dirección de difusión local. Un datagrama UDP enviado a ella llega a todos los dispositivos del segmento local.

Los nombres de dominio como "example.com" no son cadenas de host válidas en una dirección de socket. Primero hay que resolverlos a una IP; Nombres y DNS cubre la llamada getaddrinfo() que se encarga de ello.

9.11.3. Los dos roles

El ciclo de vida de un socket depende de en qué lado de la conversación se encuentre. Un socket cliente llama a connect() (o, en el caso de UDP, simplemente a sendto()) para comunicarse con un servidor conocido. Un socket servidor llama a bind() para reclamar un puerto, y luego a listen() y accept() (para TCP) o a recvfrom() (para UDP) para recibir el tráfico entrante.

El mismo constructor socket se usa en ambos casos; solo difieren los métodos que se llaman después. Las tres páginas siguientes recorren los patrones prácticos:

9.11.4. Cerrar un socket

Cada socket mantiene una pequeña porción de estado del sistema operativo (una reserva de puerto, búferes, el estado TCP de la conexión). Cuando la aplicación termina de usarlo, close() libera ese estado. Un socket olvidado es una fuga lenta que se acumula; en un bucle que abre conexiones, omitir un close acabará por agotar el conjunto de sockets disponibles de la cámara.

El patrón más limpio es la sentencia 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

Los sockets implementan el protocolo de gestor de contexto tratado en la introducción a Python, así que el bloque with garantiza que se llame a close() independientemente de si el bloque salió con normalidad o por lanzar una excepción.

9.11.5. La referencia de socket

Esta y las páginas siguientes recorren la API en forma narrativa. Para la referencia completa, a nivel de argumentos, de cada método, cada bandera y cada constante que expone el módulo, consulta socket — módulo socket. La referencia es también el lugar donde buscar las operaciones menos comunes (opciones de socket, pertenencia a grupos multicast, identificadores de ámbito de IPv6) que esta sección no cubre.