- TCP (Transmission Control Protocol) es el protocolo esencial de Internet que permite una transmisión de datos confiable y en orden incluso en entornos de red inestables
- Mientras que IP solo se encarga de entregar datos entre hosts, TCP realiza comunicación entre procesos basada en puertos y se ocupa de la recuperación de errores, retransmisión y control de orden
- Mediante flow control y congestion control, ajusta la transmisión para no exceder los límites del búfer de recepción o del ancho de banda de la red
- A través de ejemplos de un servidor TCP simple y un servidor HTTP implementados en C, se explica en detalle el proceso de creación de sockets, bind, listen, aceptación de conexiones, envío y recepción
- La estructura interna de TCP, como los números de secuencia y ACK, ventana, checksum y flags (SYN/ACK/FIN/RST), es la base clave que hace posible el funcionamiento estable del Internet actual
La necesidad y el papel de TCP
- IP solo se encarga de entregar paquetes entre hosts, y para la comunicación entre procesos se necesita una capa de transporte como TCP o UDP
- La dirección IP se compara con un “edificio” y el puerto con un “apartamento”, donde cada aplicación se comunica al enlazarse a un puerto
- TCP oculta la inestabilidad de la red, como la pérdida, duplicación o desorden de paquetes, y garantiza confiabilidad mediante retransmisión y checksum
- Los routers se mantienen simples, y la confiabilidad se maneja en ambos extremos de la comunicación, lo que reduce la complejidad de la infraestructura de red
- Gracias a esta estructura, servicios clave de Internet como HTTP, SMTP y SSH pueden funcionar de forma estable
Flow control y congestion control
- El receptor almacena temporalmente los datos mediante el receive buffer del kernel, cuyo tamaño se configura con
net.ipv4.tcp_rmem
- El emisor regula cuánto enviar a partir de la cantidad de datos que el receptor puede aceptar, indicada en el campo window
- Para evitar la congestión causada por diferencias de ancho de banda en toda la red, TCP incorpora algoritmos de congestion control
- A raíz del incidente de congestion collapse ocurrido en 1986, se añadió el mecanismo de back-off
Ejemplos de servidor TCP y servidor HTTP
- Un servidor echo TCP básico escrito en C recibe la entrada del cliente y la devuelve agregando “you sent:”
- Usa la API de sockets de Berkeley como
socket(), bind(), listen(), accept(), send() y recv()
- Cuando el servidor está en
sleep(), los datos del cliente esperan en el receive buffer y luego se procesan secuencialmente
- En un ejemplo simple de servidor HTTP/1.1, se aceptan solicitudes a través de una conexión TCP y se envían el encabezado
HTTP/1.1 200 OK y el cuerpo
- Cuenta las solicitudes con
i, y al hacer curl localhost:8080 muestra una respuesta con la forma “[1] Yo, I am a legit web server”
Estructura del segmento TCP y campos clave
- Un segmento TCP está compuesto por puerto de origen y destino, número de secuencia, número ACK, tamaño de ventana, checksum y flags
- A cada puerto se le asignan 16 bits, por lo que se pueden usar hasta 64K puertos
- Una conexión se identifica mediante la 5-tupla
(protocolo, IP de origen, puerto de origen, IP de destino, puerto de destino)
- El número de secuencia indica el rango de bytes transmitidos, y el número ACK indica los bytes recibidos correctamente
- Si faltan datos, el ACK se detiene en ese punto, y tras la retransmisión se actualiza como ACK acumulativo
- Los bits de flags controlan el estado de la conexión
SYN/ACK establecen la conexión mediante el 3-way handshake
FIN cierra la conexión mediante el 4-way handshake
RST libera la conexión de inmediato ante un cierre anormal o un error
- El campo window indica la cantidad de datos que se pueden recibir, y con el comando
ss se puede revisar el estado del búfer (rb131072, tb16384)
- El checksum detecta errores sumando unidades de 16 bits dentro del segmento
Conclusión
- TCP garantiza confiabilidad, orden e integridad, y permite que las aplicaciones funcionen correctamente incluso en entornos de Internet inestables
- Hace décadas era difícil incluso transferir unos pocos KB, pero hoy el streaming 4K es algo cotidiano
- La sofisticación del diseño y la implementación de TCP que hizo posible esta comunicación estable es la base del crecimiento continuo de Internet
1 comentarios
Comentarios en Hacker News
Si intentas construir un flujo de datos confiable sobre una capa de datagramas no confiable, al final obtienes algo casi idéntico a TCP
Las limitaciones iniciales de TCP eran un tamaño de ventana pequeño, manejo deficiente de paquetes perdidos y el hecho de que solo administraba un único flujo
Para resolver estos problemas aparecieron SCTP y QUIC
Los algoritmos de control de congestión no son parte del protocolo, sino código que se ejecuta en ambos extremos de cada conexión
Los algoritmos iniciales (Reno, Vegas, etc.) eran simples pero suficientemente efectivos, y desde entonces ha continuado la investigación para abordar búferes grandes, RTT largos, equidad y otros temas
Hace tiempo hice una librería en JavaScript que permitía controlar prioridades y cancelación de varias descargas dentro de un solo flujo
Con un script de GreaseMonkey hacía que las miniaturas de un sitio de citas se precargaran en segundo plano y según la posición del scroll
Como resultado, reduje la carga del servidor mientras mejoraba la experiencia del usuario
Curiosamente, le compartí ese script a una pareja potencial y hasta hoy seguimos juntos — en cierto modo era un Tinder antes de Tinder
TCP tiene una estructura que ofrece un circuito virtual sobre una red de conmutación de paquetes, y la idea de implementar confiabilidad mediante retransmisión provino de la red francesa Cylades
Un atacante puede inyectar datos en cualquier punto de la red o cortar la conexión con un paquete RST
Bloquear RST con un firewall mejora la estabilidad, pero los ataques de desincronización mediante números de secuencia falsificados siguen siendo posibles
Por eso, todas las aplicaciones tienen que implementar una función de reanudación en una conexión aparte, y además cargar con el problema del slow start de TCP
También me parece ineficiente el propio concepto de separar direcciones y puertos
Por ejemplo, en DNS over TLS (DoT) se pueden enviar varias consultas al mismo tiempo por una sola conexión TCP y recibir las respuestas sin importar el orden
Es más eficiente y más cortés que abrir varias conexiones
No sé si QUIC será más rápido, pero el soporte del servidor todavía es limitado
HTTP/1.1 pipelining hace algo parecido, pero las respuestas llegan en secuencia
Pero muchas clases universitarias no enfatizan este punto, así que mucha gente termina creyendo erróneamente que TCP tiene un solo algoritmo
Quisiera preguntar si alguien le tiene cariño a SCTP
SCTP es un protocolo que combina la orientación a mensajes de UDP con la confiabilidad de TCP, y soporta multistreaming y multihoming
Puede transmitir varios flujos independientes en paralelo, así que permite enviar al mismo tiempo el texto y las imágenes de una página web
Para más detalles, ver Wikipedia: Stream Control Transmission Protocol
Al final, la mejor respuesta es una capa de confiabilidad sobre UDP, es decir, QUIC
Me preguntaba si se podían enviar paquetes directamente usando solo IP
Parecía que los routers intermedios rechazarían paquetes que no fueran TCP o UDP
En IPv4 basta con especificar uno de los valores de 0 a 255 de la lista de números de protocolo de IANA
Los routers troncales no inspeccionan ese campo, aunque los equipos NAT o del ISP sí podrían hacerlo
Entre dos servidores Linux se puede incluso comunicar usando números experimentales (253, 254)
Protocolos como IPsec, GRE y L2TP tampoco son TCP/UDP
En redes corporativas con firewall o entornos con NAT, un protocolo arbitrario puede ser bloqueado
NAT rompió el principio end-to-end, y al final la gente empezó a montar todo sobre TCP o UDP, o incluso sobre HTTP
A lo mucho, el impacto sería una menor entropía en el hash de ECMP
Al final, la clave es si la otra parte entiende ese protocolo
Los números de puerto son solo identificadores de servicio dentro del nodo
RUDP (Plan9) era un excelente punto medio entre TCP y UDP
Ver Reliable User Datagram Protocol
Como TCP se volvió el valor predeterminado, terminó usándose incluso cuando no hacía falta confiabilidad ni garantía de orden
Ahora, con la expansión de HTTP/3 (basado en QUIC), la situación podría mejorar
Sin embargo, QUIC es mucho más complejo, y su potencia solo le resulta útil a algunos
Una capa de cifrado simple al estilo UDP + WireGuard podría ser una mejor alternativa
TCP es uno de los grandes inventos de la humanidad, pero no anticipó el dominio de las redes semi-conectadas (basadas en NAT)
los ingenieros de esa época probablemente preguntarían por qué complicarlo tanto a propósito
Al final, la actual estructura de enlaces asimétricos y la distinción cliente-servidor surgieron de esa forma de pensar
Los algoritmos de control de congestión de TCP tienen efectos interesantes que muchos desarrolladores desconocen
Si envías datos en una conexión nueva, la transmisión inicial es lenta, y el aumento de velocidad está determinado por la latencia
En los centros de datos, reducir el RTT apenas unos microsegundos puede mejorar mucho la velocidad
La mayoría de los stacks TCP calculan el aumento de velocidad por segmentos y no por bytes, así que con jumbo frames la subida puede ser 6 veces más rápida
AWS dedica mucho esfuerzo al bajo switching latency y al soporte para jumbo frames por esta razón
Los expertos ajustan este tipo de cosas, pero la mayoría solo se pregunta por qué no obtiene 10 Gbps en un enlace de 10 Gbps
Crear tu propio protocolo sobre IP era muy sencillo
Hasta hace 15 años, se podía experimentar en Python armando paquetes a mano