socket en Python: redes TCP y UDP

Publicado el: 27/08/2026
Tempo de leitura: 6 minutos
Close-up of electric plug and socket with vibrant lighting, showcasing technology and energy concepts.

El módulo socket proporciona la interfaz de bajo nivel para comunicación de red en Python. Permite crear clientes y servidores TCP, intercambiar datagramas UDP, trabajar con IPv4, IPv6 y sockets locales, configurar timeouts, resolver nombres y acceder a opciones del sistema operativo. Bibliotecas de HTTP, SMTP, bases de datos y mensajería se construyen sobre conceptos de transporte similares.

Los sockets transportan bytes, no mensajes Python. La aplicación debe definir framing, encoding, límites, deadlines, autenticación y manejo de desconexión. Para un protocolo estándar, prefiere una biblioteca madura de alto nivel. Usa socket al implementar o estudiar un protocolo, integrar un servicio especializado o necesitar control detallado.

Familias de direcciones y tipos

AF_INET representa IPv4, AF_INET6 representa IPv6 y AF_UNIX, cuando existe, ofrece comunicación local por pathname. TCP normalmente usa SOCK_STREAM; UDP utiliza SOCK_DGRAM.

import socket

cliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
    cliente.settimeout(5)
    cliente.connect(("example.com", 80))
finally:
    cliente.close()

Prefiere un context manager para cerrar el descriptor incluso cuando ocurre una excepción.

Conecta con create_connection

socket.create_connection() resuelve el host e intenta direcciones adecuadas, simplificando clientes TCP.

import socket

with socket.create_connection(("example.com", 80), timeout=5) as sock:
    sock.sendall(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
    respuesta = sock.recv(4096)
    print(respuesta[:100])

Para HTTP de producción, utiliza una biblioteca HTTP. El ejemplo muestra únicamente la capa de transporte.

TCP es un flujo de bytes

TCP entrega un flujo ordenado. Una llamada a send() en un lado no corresponde necesariamente a una llamada a recv() en el otro. Los datos pueden llegar divididos o agrupados.

El protocolo de aplicación debe indicar dónde termina cada mensaje mediante delimitador validado, header fijo, prefijo de longitud o formato autodescriptivo.

send y sendall

send() puede transmitir solo parte del buffer y devuelve la cantidad aceptada. sendall() continúa hasta enviar todo o encontrar un error.

mensaje = b"datos importantes"
sock.sendall(mensaje)

Incluso después de sendall(), el receptor debe reconstruir el mensaje. El éxito significa que el sistema local aceptó los bytes, no que la aplicación remota los procesó.

recv y cierre ordenado

recv(tamano) devuelve hasta la cantidad solicitada. Un bytes vacío indica que el peer cerró su dirección de envío correctamente.

partes = []
while True:
    bloque = sock.recv(4096)
    if not bloque:
        break
    partes.append(bloque)
datos = b"".join(partes)

No esperes EOF cuando el protocolo mantiene la conexión abierta para múltiples mensajes; usa framing.

Framing con prefijo de longitud

Un diseño común envía primero un tamaño fijo y después el payload.

import struct


def recibir_exacto(sock, cantidad):
    partes = []
    restante = cantidad
    while restante:
        bloque = sock.recv(restante)
        if not bloque:
            raise ConnectionError("conexión cerrada")
        partes.append(bloque)
        restante -= len(bloque)
    return b"".join(partes)

header = recibir_exacto(sock, 4)
tamano = struct.unpack("!I", header)[0]
if tamano > 1_000_000:
    raise ValueError("mensaje demasiado grande")
payload = recibir_exacto(sock, tamano)

Valida el tamaño declarado antes de reservar memoria.

Servidor TCP básico

Un servidor crea el socket, asocia una dirección, escucha y acepta conexiones.

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as servidor:
    servidor.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    servidor.bind(("127.0.0.1", 9000))
    servidor.listen()
    conexion, direccion = servidor.accept()
    with conexion:
        conexion.sendall(b"hola\n")

Asociar a 127.0.0.1 restringe acceso a la máquina local. Escuchar en todas las interfaces expone el servicio y exige autenticación, firewall, límites y hardening.

listen y backlog

listen() coloca el socket en modo pasivo. El backlog influye en la cola de conexiones pendientes, aunque el comportamiento exacto depende del sistema.

Un backlog grande no arregla un servidor lento. Acepta rápidamente, limita clientes y configura timeouts.

accept devuelve otro socket

accept() devuelve un nuevo socket conectado y la dirección remota. El socket de escucha sigue disponible.

Cierra ambos de forma independiente. Filtrar conexiones aceptadas agota descriptores.

Concurrencia del servidor

Un servidor mínimo atiende un cliente por vez. Para varios clientes, usa threads, procesos, selectors o asyncio. La elección depende de cantidad de conexiones, workload, latencia y complejidad.

select en Python explica multiplexación de descriptores. No crees una thread ilimitada por conexión.

Timeouts

settimeout(segundos) limita operaciones bloqueantes.

sock.settimeout(10)
try:
    datos = sock.recv(4096)
except socket.timeout:
    registrar_aviso("cliente inactivo")

Define deadlines de conexión, lectura y escritura según el protocolo. Una conexión sin límite puede ocupar un worker indefinidamente.

Modo no bloqueante

setblocking(False) hace que las llamadas vuelvan inmediatamente y lancen BlockingIOError cuando todavía no pueden avanzar.

No construyas un busy loop. Usa selectors, select o un event loop.

UDP

UDP envía datagramas independientes sin entrega fiable, orden, retransmisión ni estado de conexión.

import socket

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
    sock.settimeout(2)
    sock.sendto(b"consulta", ("127.0.0.1", 9999))
    datos, origen = sock.recvfrom(2048)
    print(origen, datos)

Los datagramas pueden perderse, duplicarse, reordenarse o truncarse si el buffer es pequeño. La aplicación define retries e idempotencia.

Tamaño de UDP

Aunque UDP puede representar datagramas grandes, las redes reales tienen MTU y fragmentación. Los mensajes pequeños son más robustos. Usa TCP u otro protocolo para payloads grandes o fiables.

Resolución de nombres

getaddrinfo() resuelve un hostname y devuelve alternativas con familia, tipo, protocolo y dirección.

for resultado in socket.getaddrinfo("example.com", 443, type=socket.SOCK_STREAM):
    familia, tipo, protocolo, canonico, direccion = resultado
    print(familia, direccion)

DNS puede ser lento, fallar o devolver varias direcciones. No guardes una respuesta para siempre sin política.

IPv4 e IPv6

Usa getaddrinfo() e intenta las direcciones devueltas en lugar de asumir IPv4. Las tuplas IPv6 difieren y el dual stack puede requerir configuración específica.

Prueba despliegues IPv4-only, IPv6-only y dual stack.

Puertos y orden de bytes

Los puertos van de 0 a 65535 y los bajos pueden requerir privilegios. Funciones como htons(), htonl(), ntohs() y ntohl() convierten orden de bytes. Los protocolos binarios suelen usar struct con prefijo !.

SO_REUSEADDR

SO_REUSEADDR puede facilitar reinicio de servidores cuando quedan conexiones cerrándose. Su semántica varía y no significa que varios servidores independientes deban compartir una puerta.

Configura opciones antes de bind().

Keepalive

SO_KEEPALIVE habilita probes del sistema para detectar conexiones rotas, pero los intervalos por defecto pueden ser largos y el tuning es específico de plataforma.

Keepalive no sustituye heartbeats y deadlines de aplicación.

shutdown

shutdown(socket.SHUT_WR) indica que el programa no enviará más datos mientras puede seguir recibiendo. close() libera el descriptor local.

Usa half-close solo cuando el protocolo defina su significado.

TLS

Un socket TCP plano no ofrece confidencialidad, autenticación del peer ni protección frente a intermediarios. Envuélvelo con un ssl.SSLContext correctamente configurado o utiliza un cliente seguro de alto nivel.

No inventes criptografía ni desactives verificación de certificados como solución permanente.

Encoding

La red transporta bytes. Define el encoding de texto explícitamente.

mensaje = "hola".encode("utf-8")
sock.sendall(mensaje)
texto = datos.decode("utf-8", errors="strict")

Los delimitadores se definen como bytes y las secuencias inválidas necesitan una política.

Seguridad de entrada

Limita tamaño, profundidad, cantidad de campos y tiempo de procesamiento. Nunca pases datos de red directamente a eval(), shell, SQL o deserializadores inseguros.

Autentica clientes cuando sea necesario y autoriza cada operación.

Clientes lentos

Un cliente puede enviar pocos bytes lentamente y ocupar un worker. Usa deadlines, progreso mínimo, límites de conexiones y multiplexación.

Rate limiting y backpressure deben proteger memoria y servicios downstream.

Fallos transitorios

Las conexiones fallan por DNS, timeout, reset, routing, refusal o indisponibilidad temporal. Reintenta solo operaciones idempotentes, con límite y backoff exponencial.

No repitas indefinidamente ni trates un fallo de autenticación como transitorio.

Sockets locales Unix

Cuando AF_UNIX está disponible, procesos de una máquina pueden comunicarse mediante pathname con menor exposición a la red.

Gestiona permisos, elimina paths antiguos con cuidado y restringe el directorio.

Pruebas

Prueba frames divididos, varios frames juntos, EOF, timeout, reset, direcciones inválidas, IPv6, DNS múltiple, clientes lentos, payload máximo, conexiones simultáneas, shutdown y pérdida de red.

Usa sockets locales y puertos efímeros. Evita depender de servicios públicos.

Observabilidad

Registra dirección, duración, bytes, estado del protocolo y categoría de error sin guardar secretos o payloads sensibles. Métricas de conexiones activas, timeouts, resets y colas muestran saturación.

Errores comunes

Los fallos frecuentes son suponer que recv() devuelve un mensaje completo, ignorar envíos parciales, omitir timeouts, exponer el servidor accidentalmente, esperar fiabilidad de UDP, asignar una thread ilimitada por cliente, tratar DNS como identidad y enviar datos sensibles sin TLS.

Conclusión

socket ofrece control directo de red, pero exige un protocolo explícito. Define framing, límites, timeouts, seguridad, lifecycle y concurrencia antes de desplegar.

Consulta la documentación oficial de socket y select en Python para multiplexar conexiones.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Código Python asíncrono en un portátil para inspect.markcoroutinefunction
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    markcoroutinefunction: detecta wrappers async

    Aprende inspect.markcoroutinefunction en Python para identificar wrappers asíncronos, integrar frameworks y evitar detecciones incorrectas.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Código Python para recorrer carpetas y archivos con Path.walk
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    Path.walk: recorre directorios con seguridad

    Aprende Path.walk en Python para recorrer directorios, filtrar archivos, tratar errores y controlar la travesía con seguridad.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Depuración de un proceso Python en terminal con código
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pdb -p: depura procesos Python en ejecución

    Aprende a conectar pdb a un proceso Python en ejecución, inspeccionar la pila y diagnosticar bloqueos de forma segura.

    Ler mais

    Tempo de leitura: 6 minutos
    09/10/2026
    Código Python para representar fracciones exactas
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    fractions.from_number: convierte números en fracciones

    Aprende fractions.from_number en Python para convertir números en fracciones exactas, controlar precisión, validar entradas y evitar redondeos inesperados.

    Ler mais

    Tempo de leitura: 4 minutos
    09/10/2026
    Desarrollador configurando un servidor HTTPS y certificado TLS con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crea un servidor HTTPS local en Python

    Aprende HTTPSServer en Python para crear servicios HTTPS locales, configurar certificados, usar hilos y comprender sus límites.

    Ler mais

    Tempo de leitura: 4 minutos
    08/10/2026
    Archivos protegidos que representan extracción segura de TAR con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extrae TAR con seguridad

    Aprende tarfile extraction_filter en Python para extraer archivos TAR con validación, seguridad y control de rutas.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026