TCP (Transmission Control Protocol) y UDP (User Datagram Protocol) son los dos transportes básicos del modelo TCP/IP. Ambos viajan sobre IP y usan puertos para multiplexar aplicaciones, pero su semántica, garantías y costes son muy distintos. Esta guía técnica repasa cómo funcionan por dentro, qué garantías ofrecen, qué problemas resuelven (y cuáles no), y cómo medir y ajustar cada uno en producción.
1) Visión de alto nivel
- UDP prioriza baja latencia y mínima sobrecarga. No establece conexión, no confirma entregas, no ordena paquetes ni reenvía pérdidas. Ideal cuando llegar rápido importa más que llegar siempre (voz, vídeo interactivo, juegos en tiempo real, DNS, telemetría ligera) o cuando la lógica de fiabilidad vive en la aplicación (FEC/ARQ propios, QUIC/HTTP/3).
- TCP prioriza fiabilidad y control. Establece conexión (three-way handshake), entrega bytes en orden y sin duplicados, retransmite pérdidas, regula el emisor (control de flujo) y cuida la red (control de congestión). Es la base de HTTP/1.1, HTTP/2 (TLS), SMTP, IMAP, FTP y cualquier tráfico que requiera integridad de datos.
2) Cabeceras y campos (lo que inspecciona Wireshark)
UDP — 8 bytes fijos
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| SrcPort| DstPort| Length | Check |
+--------+--------+--------+--------+
- Source/Destination Port (16b): puertos de origen y destino.
- Length (16b): longitud (cabecera + datos).
- Checksum (16b): obligatorio en IPv6, opcional en IPv4 (recomendado). Cubre pseudo-cabecera IP para detectar corr y direcciones equivocadas.
Sin opciones; la simplicidad es su virtud (y su límite).
TCP — 20 bytes base + opciones
0 7 8 15 16 31
+--------+--------+----------------+
| SrcPort| DstPort| Sequence Num |
+--------+--------+----------------+
| Acknowledgment Number |
+---+----+--------+----+----------+
|HL | RS | Flags |Win | Check |Urg|
+---+----+--------+----+----------+
| Options (MSS, WS, SACK, TS) |
+---------------------------------+
Lenguaje del código: JavaScript (javascript)
- Sequence/Ack Numbers (32b): control de orden y confirmaciones.
- Data Offset (HL): tamaño de cabecera.
- Flags: SYN, ACK, FIN, RST, PSH, URG (más NS, CWR, ECE).
- Window Size (16b): control de flujo (buffer del receptor).
- Checksum: obligatorio (con pseudo-cabecera IP).
- Options (variable): MSS, Window Scale (WS), SACK Permitted y SACK blocks, Timestamps (TS), NOP, etc.
3) Establecimiento y cierre de conexión (TCP)
Three-Way Handshake
- SYN → cliente anuncia ISN (initial sequence number) y opciones (MSS, WS, SACK, TS).
- SYN-ACK ← servidor confirma y propone sus opciones.
- ACK → conexión establecida; comienza el flujo byte-stream.
Cierre
- FIN/ACK en cada dirección (semicierres). Puede aparecer TIME_WAIT (típico del lado que cierra), esencial para evitar duplicados tardíos.
- RST aborta conexión de forma inmediata (error).
Estados relevantes: LISTEN, SYN_SENT, SYN_RECEIVED, ESTABLISHED, FIN_WAIT_1/2, CLOSE_WAIT, CLOSING, LAST_ACK, TIME_WAIT.
4) Garantías y mecanismos (TCP)
- Fiabilidad: checksum + retransmisión. Un segmento perdido se detecta (timeouts o triple duplicate ACK) y se reenvía.
- Orden: entrega estrictamente in-order (no hay “gaps” hacia la aplicación). Esto introduce Head-of-Line Blocking: una pérdida bloquea todo lo posterior hasta que se recupere.
- Control de flujo: el receptor anuncia ventana (Window) para no saturar su buffer.
- Control de congestión: protege la red ajustando el congestion window (cwnd). Algoritmos destacados:
- Reno/NewReno: AIMD clásico, Slow Start, Fast Retransmit/Recovery.
- CUBIC (Linux por defecto): crecimiento cúbico, mejor en BDP alto.
- BBR: estima BW y RTT para evitar colas y llenar el pipe sin pérdidas.
- Temporizadores: RTO (Retransmission Timeout) según RTT y su varianza (Jacobson/Karels), Karn’s Algorithm (no medir RTT en retransmitidos), Delayed ACK (retrasar levemente ACK para piggyback y reducir overhead).
- Opciones clave:
- MSS: tamaño máximo de segmento (sin cabeceras IP/TCP). Evita fragmentación IP.
- Window Scale: amplía ventana > 65.535 (redes de alto BDP).
- SACK: ACK selectivos para recuperaciones rápidas con pérdidas múltiples.
- Timestamps: RTT preciso, PAWS (Protección contra reordenamientos).
5) Rendimiento y MTU/MSS
- MTU (p. ej., 1.500 en Ethernet) delimita el tamaño máximo de IP. La MSS ideal ≈ MTU − 40 (IPv4+TCP sin opciones) o MTU − 60 (IPv6+TCP).
- Activar PMTUD (Path MTU Discovery) evita fragmentación IP. Asegúrate de no filtrar ICMP Fragmentation Needed.
- En VPN/GRE/WireGuard, reduce MSS (ej. MSS clamping a 1.360–1.420) para los overheads del túnel.
- Offloads: TSO/GSO/GRO reducen carga CPU al segmentar/coalescer en NIC.
6) UDP en serio: cuándo sí y cómo
- Multicast: UDP soporta unicast, multicast y broadcast (TCP sólo unicast). Vital para descubrimiento (mDNS/SSDP), routing (OSPF, RIP), streaming (RTP).
- Tiempo real: voz/vídeo interactivos toleran pequeñas pérdidas pero no la latencia añadida por retransmisiones; UDP es la base de RTP, VoIP, WebRTC (encima usa DTLS/SRTP).
- DNS: usa UDP por defecto (rápido); si la respuesta es truncada (TC bit) o grande (DNSSEC/EDNS0), reintenta en TCP.
- Fiabilidad a nivel aplicativo: si la necesitas, añade FEC/ARQ, numeración y timers en la aplicación (o usa QUIC, ver más abajo).
Chequeo: en IPv6, la checksum de UDP es obligatoria; en IPv4 es opcional (mejor activarla).
7) QUIC/HTTP-3: fiable sobre UDP (y por qué importa)
- QUIC implementa fiabilidad, control de congestión y seguridad (TLS 1.3 integrado) en user-space sobre UDP. Evita Head-of-Line a escala de stream (multiplexación), permite migration (cambio de IP/port sin cortar sesión), y acelera handshakes.
- HTTP/3 corre sobre QUIC. Ventaja: menor latencia en arranque y mejor comportamiento ante pérdidas y reordenamientos que TCP+TLS+HTTP/2.
8) Seguridad, NAT y middleboxes
- TLS vs DTLS: TLS (TCP) para fiabilidad; DTLS (UDP) para tiempo real con cifrado.
- Ataques:
- SYN flood (TCP): mitigar con SYN cookies, backlog tuning, BPF.
- Amplificación UDP (DNS, NTP, Memcached): filtrar IP de origen falsificada (BCP 38), rate limiting, RRL en DNS.
- NAT:
- TCP: NAT conoce estados (SYN→ESTABLISHED→TIME_WAIT); mapeos duran más.
- UDP: mapeos expiran rápido; usa keepalives cortos (STUN/ICE) en tiempo real.
- Firewalls: el estado (stateful) sigue secuencias TCP; en UDP depende de time-outs y reglas específicas.
- Multicast: atraviesa dominios L3 con IGMP/MLD (acceso) y PIM (core). Muchos NAT lo bloquean por defecto.
9) Medición y observabilidad
- tcpdump/Wireshark:
- TCP handshake:
tcp.flags.syn==1 && tcp.flags.ack==0, RTT inicial, MSS/WS/SACK/TS. - UDP: puertos, length, checksum, pérdida aparente (se infiere por aplicación).
- TCP handshake:
- ss / netstat: estados ESTABLISHED, TIME_WAIT, CLOSE_WAIT; colas send/recv.
- iperf3:
- TCP: mide throughput con control de congestión real.
- UDP: define bitrate objetivo; observa jitter y loss (
-u -b 100M -l 1400 -R).
- Métricas clave:
- TCP: RTT, RTO, cwnd, retransmissions, out-of-order, SACKed, zero-window, p99 latency.
- UDP: loss %, jitter, reorder, arrival variance.
10) Tuning (con cabeza)
TCP
- Congestión: CUBIC (default Linux), considera BBR para WAN/alto BDP (
net.ipv4.tcp_congestion_control=bbr). - Buffers: ajustar
tcp_rmem/tcp_wmem, auto-tuning en Linux suele bastar. - Nagle/Delay:
TCP_NODELAY(latencia) vs Nagle (agregación); delayed ACK puede aumentar latencia de apps chateadoras (evalúa). - Keepalive: revisa intervalos (
tcp_keepalive_*) y políticas de NAT/ALB. - TIME_WAIT: no lo “mates” indiscriminadamente; ajusta puertos efímeros, SO_REUSEADDR/PORT, escalado horizontal.
UDP
- Buffers:
SO_RCVBUF/SO_SNDBUFmayores para flujos intensos; GRO/GSO si NIC/OS lo permite. - Rate control: hazlo en la app (token-bucket); adapta a feedback (loss/jitter).
- Keepalive NAT: paquetes ligeros periódicos (STUN/ICE en RTC).
11) Casos prácticos y patrones de diseño
- Streaming en vivo interactivo → UDP/QUIC + FEC + control de tasa; prioriza latencia/jitter sobre pérdida mínima.
- Entrega de ficheros/backup → TCP con SACK, Window Scale, BBR en WAN; PMTUD correcto.
- DNS autoritativo/recursivo → UDP por defecto; TCP fallback (truncation, DNSSEC); considera DoT/DoH.
- APIs web → HTTP/2 sobre TCP o HTTP/3 (QUIC) si controlas clientes y deseas menor latencia de inicio/cambio de red.
- Juegos on-line → UDP con reconstrucción de estado y predicción del cliente; evita HOL.
12) Tabla comparativa (resumen)
| Dimensión | TCP | UDP |
|---|---|---|
| Conexión | Sí (handshake) | No |
| Fiabilidad | Sí (retransmisión, orden) | No (a cargo de la app si se necesita) |
| Orden | Garantizado (byte-stream) | No (posible reorden) |
| Congestión | Sí (Reno/CUBIC/BBR…) | No (debe hacerlo la app o QUIC) |
| Latencia | Mayor (HOL, handshake, control) | Baja (sin handshake, sin HOL) |
| Multicast | No | Sí |
| Seguridad “nativa” | TLS (sobre TCP) | DTLS (sobre UDP); QUIC integra TLS |
| Uso típico | Web, correo, bases de datos, file-transfer | RTP/VoIP, gaming, DNS, telemetry, QUIC/HTTP-3 |
Conclusiones
- TCP es el transporte por defecto cuando necesitas integridad y orden, y el coste en latencia es asumible. Su rendimiento real depende de RTT, BDP, opciones (MSS/WS/SACK/TS) y del algoritmo de congestión.
- UDP es tu herramienta cuando prima la latencia baja o necesitas multicast, o cuando la aplicación ya implementa su propia lógica de fiabilidad (QUIC, FEC/ARQ). Su éxito depende de rate control, buffers y tolerancia a pérdidas/jitter.
- HTTP/3/QUIC borra parte de la frontera: fiabilidad y seguridad sobre UDP, resolviendo HOL a nivel de stream y acelerando handshakes.
Elegir bien no es “TCP vs UDP”, sino qué garantía necesitas y dónde la implementas: red, transporte o aplicación. Mide (RTT, pérdida, jitter, p99), ajusta con prudencia y valida en producción con iperf, tcpdump/Wireshark y métricas. Así es como los transportes trabajan para tu servicio, y no al revés.