El Transmission Control Protocol (TCP) es el cimiento de casi todo el tráfico confiable de Internet. Establece conversaciones persistentes, numera cada byte y aplica mecanismos que corrigen pérdidas o duplicados sin que la aplicación deba intervenir.
La IETF normalizó el protocolo en documentos como RFC 793 y su actualización RFC 9293, lo que permitió que sistemas operativos muy distintos se entiendan con exactitud bit a bit. Este apartado describe cómo se forma y se mantiene una sesión TCP, cómo se numeran los datos y cómo se reacciona ante cada evento de la red.
TCP combina tres ideas: conexión lógica, control de estado y confiabilidad extremo a extremo. Una conexión lógica significa que ambos extremos acuerdan parámetros antes de enviar datos. El control de estado implica que cada host conoce las transiciones posibles para no mezclar conversaciones. Finalmente, la confiabilidad extremo a extremo se logra numerando bytes, confirmando recepciones y ajustando el ritmo con ventanas deslizantes.
Estas características hacen que TCP sea la opción natural para aplicaciones que no pueden tolerar huecos como HTTP, SMTP o SSH, mientras que UDP queda reservado para escenarios donde la velocidad prima sobre la garantía de entrega.
El three-way handshake coordina números de secuencia iniciales (ISN) y reserva recursos en ambos equipos antes de transportar datos.
| Paso | Host | Objetivo |
|---|---|---|
| 1 | Cliente | Envía SYN con su ISN y anuncia el tamaño inicial de ventana de recepción. |
| 2 | Servidor | Responde con SYN-ACK: confirma el ISN del cliente (ACK) y publica su propio ISN. |
| 3 | Cliente | Envía ACK confirmando el ISN del servidor y queda lista la sesión para intercambiar datos. |
En una captura de Wireshark se aprecian tres segmentos consecutivos donde el flag SYN aparece primero en uno, luego junto al ACK y finalmente se observa un ACK aislado. Si la red descarta el primer SYN, el cliente reintenta con un temporizador exponencial y puede abandonar la conexión tras superar el número de reintentos configurado.
Finalizar una sesión también requiere coordinación. El proceso clásico utiliza cuatro mensajes porque cada dirección de la comunicación se cierra por separado.
TIME-WAIT dura al menos dos veces el RTT estimado, evitando que una nueva conexión reutilice puertos que podrían recibir segmentos rezagados. Ante un problema grave, cualquiera de los extremos puede enviar RST para abortar inmediatamente la sesión, sacrificando la posibilidad de retransmisión controlada.
Cada byte transmitido por TCP recibe un número dentro de un espacio de 32 bits. El ISN es aleatorio para evitar ataques de predicción. El campo ACK indica el próximo número que el receptor espera, por lo que implícitamente confirma todo lo anterior. Si el emisor envía 100 bytes y recibe un ACK con valor ISN+101 significa que todo llegó y puede liberar memoria.
Cuando llegan datos fuera de orden, el receptor puede almacenar los segmentos y reenviar ACK duplicados para avisar qué byte falta. Al recibir tres ACK duplicados, el emisor ejecuta fast retransmit y vuelve a mandar el segmento ausente sin esperar al temporizador general.
Este script corta un mensaje en segmentos, simula ACK duplicados y muestra cómo se mueve la ventana de envío:
from collections import deque
def segmentar(mensaje, tamano):
for inicio in range(0, len(mensaje), tamano):
yield inicio, mensaje[inicio:inicio + tamano]
def simular_tcp(mensaje, tam_segmento=12, ventana=3):
pendientes = deque(segmentar(mensaje, tam_segmento))
enviados = []
numero_base = 1
while pendientes or enviados:
while len(enviados) < ventana and pendientes:
numero, datos = pendientes.popleft()
print(f"ENVIO SEQ={numero_base + numero}: {datos!r}")
enviados.append((numero_base + numero, datos))
if enviados:
seq, datos = enviados.pop(0)
if "perdida" in datos:
print(f"ACK duplicado por falta del SEQ {seq}")
enviados.insert(0, (seq, datos))
else:
numero_base = seq + len(datos)
print(f"ACK {numero_base} recibido, ventana avanza")
texto = "TCP reenvia datos cuando detecta perdida y ajusta la ventana"
simular_tcp(texto)
La consola muestra cómo los ACK devuelven espacio en la ventana y cómo un segmento perdido queda al frente hasta que se confirma.
Los temporizadores de TCP aseguran que una pérdida no se vuelva permanente. El más conocido es el RTO (Retransmission Timeout), calculado a partir del RTT suavizado (SRTT) y su variación (RTTVAR). El algoritmo de Jacobson/Karels ajusta estos valores de manera dinámica.
Estos temporizadores coordinan el reenvío de paquetes perdidos y mantienen la sesión viva incluso en enlaces de alta latencia. Una mala configuración puede sobrecargar la red si el RTO es demasiado corto o volver la conexión lenta si es exageradamente largo.
Cada segmento contiene una cabecera fija de 20 bytes y una sección opcional con características como escalado de ventana o timestamps. Los campos principales son los siguientes:
| Campo | Propósito |
|---|---|
| Puerto origen / destino | Identifican proceso emisor y receptor. |
| Número de secuencia | Marca el primer byte de los datos contenidos en el segmento. |
| Número de ACK | Indica el siguiente byte esperado. |
| Data offset | Señala el inicio de los datos e informa el tamaño de opciones. |
| Flags | Controlan el estado de la sesión (SYN, ACK, FIN, RST, PSH, URG, ECE, CWR). |
| Tamaño de ventana | Mide cuántos bytes adicionales puede recibir el host. |
| Checksum | Valida que ni la cabecera ni los datos llegaran corruptos. |
| Puntero urgente | Identifica información marcada como urgente cuando URG está activo. |
| Opciones | Permiten negociar MSS, timestamps, SACK o escalado de ventana. |
Gracias a la segmentación, cada flujo puede adaptarse al MTU del enlace sin desperdiciar ancho de banda ni forzar fragmentación en capas inferiores.
Los flags ocupan un solo byte pero definen la mitad de la lógica de TCP. Su combinación describe eventos como apertura, cierre o prioridad.
| Flag | Descripción |
|---|---|
| SYN | Solicita apertura de sesión y transporta el ISN. |
| ACK | Confirma recepciones. Está presente en casi todos los segmentos posteriores al handshake. |
| FIN | Inicia un cierre ordenado de una dirección del canal. |
| RST | Aborta la sesión de inmediato ante errores graves o puertos no escuchando. |
| PSH | Indica que los datos deben entregarse enseguida a la aplicación, sin esperar a llenar buffers. |
| URG | Marca datos urgentes y habilita el puntero correspondiente. |
| ECE / CWR | Soportan congestion notification explícita, permitiendo reaccionar antes de perder paquetes. |
Tanto PSH como URG se usan menos en aplicaciones modernas, pero resultan útiles en protocolos interactivos que priorizan la latencia.
Capturar un flujo HTTP revela en segundos los conceptos teóricos. Al iniciar la captura se ve el three-way handshake, luego un estallido de segmentos con PSH cuando se intercambian encabezados y finalmente un four-way handshake al cerrar la sesión. Activar la columna “Bytes in flight” en Wireshark permite estimar la ventana efectiva.
Cuando se producen pérdidas, Wireshark marca los retransmissions y los Fast Retransmissions en rojo o naranja. Comparar los RTT de cada segmento ayuda a detectar enlaces saturados o firewalls que agregan latencia.
Windows expone comandos que permiten comprobar si un puerto TCP responde sin instalar herramientas adicionales.
Test-NetConnection -ComputerName www.example.com -Port 443 -InformationLevel Detailed
Get-NetTCPConnection -State Established | Select-Object -First 5
Test-NetConnection realiza el three-way handshake y devuelve el RTT estimado, el estado del puerto y la dirección IP resuelta.
Get-NetTCPConnection lista las sesiones activas con sus puertos, lo que facilita detectar conexiones huérfanas o el abuso de puertos efímeros.
TCP es mucho más que un contenedor de bytes: es una máquina de estados cuidadosamente diseñada para convivir con redes imperfectas. Su three-way handshake, la numeración de secuencias y los temporizadores de retransmisión proporcionan la confiabilidad que innumerables aplicaciones necesitan. En el siguiente tema se analizará cómo los puertos TCP permiten identificar servicios específicos dentro de un mismo host y habilitan la multiplexación masiva de conexiones.