10. Multiplexación y sockets

Un socket es la combinación de dirección IP y puerto que identifica una conversación de transporte. Gracias a esta tupla, los sistemas operativos pueden multiplexar cientos o miles de conexiones sobre la misma interfaz física sin mezclarlas.

La multiplexación permite que un servidor web atienda a múltiples clientes simultáneamente, que un mismo host aloje varios servicios y que los routers puedan distinguir flujos incluso cuando comparten IP mediante NAT.

10.1 Definición formal de socket

Un socket TCP queda definido por cuatro valores: {IP_origen, puerto_origen, IP_destino, puerto_destino}. Esta cuádrupla es única en el tiempo y permite distinguir conexiones aunque los mismos hosts se comuniquen varias veces.

  • La IP identifica el host dentro de la red.
  • El puerto indica el proceso dentro del host.
  • El protocolo (TCP/UDP) completa el contexto, aunque en la jerga cotidiana se lo da por supuesto.

La suma de IP+puerto es la clave que utiliza el sistema operativo para enrutar los segmentos al socket correcto en la pila de transporte.

10.2 Multiplexación de conexiones simultáneas

Cuando un servidor escucha en un puerto bien conocido (por ejemplo 443), cada conexión entrante genera un socket distinto:

  1. El proceso llama a listen y queda atento en el puerto elegido.
  2. Por cada cliente que inicia el handshake, el servidor acepta y crea un socket hijo con la cuádrupla completa.
  3. El socket padre sigue en estado LISTEN para recibir nuevas solicitudes.

Este esquema permite que cientos de clientes compartan el mismo puerto destino (443) siempre y cuando usen puertos de origen diferentes.

10.3 Comunicación cliente-servidor

Un cliente suele elegir un puerto efímero, iniciar el handshake y, una vez establecida la conexión, intercambiar datos con el servidor. Cada mensaje de aplicación se encapsula en segmentos etiquetados con la cuádrupla correspondiente, lo que garantiza que la respuesta volverá al socket correcto.

Los servidores modernos pueden usar modelos bloqueantes, no bloqueantes o basados en eventos (como select, poll, epoll) para administrar cientos de sockets simultáneos sin saturar la CPU.

10.4 Ejemplo práctico: HTTP

Una conexión HTTP típica se describe como:

Cliente: puerto aleatorio 51532 → Servidor: 203.0.113.10:80

Mientras la sesión está activa, cada segmento trae esos valores. Si otro cliente abre la web, usará el mismo IP destino y puerto 80, pero un puerto de origen diferente (por ejemplo 51533), lo que evita colisiones.

10.5 Sockets y NAT

Los dispositivos NAT expanden la idea de multiplexación: traducen las cuádruplas privadas a cuádruplas públicas. Al mantener una tabla interna, pueden asociar cada puerto externo con un host interno y reenviar los segmentos apropiados.

Esta técnica permite que docenas de dispositivos compartan una sola dirección IP pública sin interferirse.

10.6 Multiplexación en la aplicación

Algunas aplicaciones multiplexan lógicamente múltiples flujos sobre un mismo socket TCP (por ejemplo HTTP/2, HTTP/3 sobre QUIC). Aunque el transporte ve una sola conexión, la capa de aplicación define streams independientes con identificadores propios.

Este enfoque reduce el número de sockets abiertos y mejora la eficiencia cuando existen muchas solicitudes concurrentes entre dos hosts conocidos.

10.7 Inspección de sockets en el sistema

Administradores y desarrolladores pueden auditar los sockets activos para confirmar que los servicios escuchan donde corresponde.

PowerShell

Get-NetTCPConnection -State Listen |
  Select-Object -First 5 -Property LocalAddress, LocalPort, OwningProcess

Get-NetTCPConnection -RemotePort 443 |
  Select-Object -First 5 -Property LocalAddress, LocalPort, RemoteAddress, State

El primer comando lista sockets en escucha; el segundo muestra conexiones hacia el puerto 443 para verificar cuántos clientes están utilizando HTTPS desde el host actual.

10.8 Ejemplo en Python: multiplexación con select

El siguiente ejemplo crea un servidor eco que atiende múltiples clientes usando select para esperar eventos en varios sockets a la vez:

Servidor eco no bloqueante

import select
import socket

def servidor_echo(host="0.0.0.0", puerto=5000):
    servidor = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    servidor.setblocking(False)
    servidor.bind((host, puerto))
    servidor.listen()
    sockets = {servidor}

    print(f"Escuchando en {host}:{puerto}")
    while True:
        listos, _, _ = select.select(sockets, [], [])
        for sock in listos:
            if sock is servidor:
                cliente, direccion = servidor.accept()
                cliente.setblocking(False)
                sockets.add(cliente)
                print("Conexión aceptada", direccion)
            else:
                datos = sock.recv(1024)
                if datos:
                    sock.sendall(datos)
                else:
                    sockets.remove(sock)
                    sock.close()

servidor_echo()

Cada cliente aceptado se integra en el conjunto de sockets vigilados. select permite multiplexar los eventos de lectura sin crear un hilo por conexión, demostrando cómo la capa de transporte y la aplicación cooperan para escalar.

10.9 Buenas prácticas

  • Documentar puertos y servicios para evitar conflictos durante despliegues.
  • Configurar timeouts y límites de conexiones por cliente para impedir abusos.
  • Usar mecanismos asíncronos (select, poll, IOCP, epoll) cuando el número de sockets activos crece por encima de unas pocas centenas.

10.10 Cierre

La multiplexación por sockets es el secreto que permite que Internet funcione a gran escala. Dominar este concepto facilita diseñar servicios resilientes, comprender capturas de red complejas y diagnosticar cuellos de botella en servidores con alta concurrencia.