9. Segmentación y numeración de paquetes

TCP transforma flujos de bytes arbitrarios en segmentos manejables para la red. Cada segmento transporta números de secuencia que permiten reensamblar el mensaje original incluso si los paquetes llegan tarde, duplicados o fuera de orden.

Comprender la segmentación y la numeración es clave para explicar por qué las capturas de Wireshark muestran ACK aparentemente repetidos, cómo se detectan huecos y cómo la capa de transporte corrige los problemas antes de que impacten a la aplicación.

9.1 ¿Qué es un segmento?

Un segmento TCP es la unidad que viaja entre hosts. Combina una cabecera con números de puerto, secuencias y flags, seguida por datos de aplicación. Su tamaño depende del MSS (Maximum Segment Size) negociado durante el three-way handshake y del MTU disponible en la ruta.

  • El MSS suele ser MTU - 40 bytes (20 de IP + 20 de TCP), por ejemplo 1460 en redes Ethernet estándar.
  • Los segmentos pueden ser más pequeños si la aplicación envía mensajes cortos o si Nagle junta varios envíos en uno solo.
  • Un segmento contiene un rango contiguo de bytes numerados que la otra parte usará para reordenar los datos.

9.2 Numeración de bytes

Cada conexión elige un número de secuencia inicial aleatorio (ISN). A partir de ahí cada byte transmitido incrementa el contador en uno. Cuando el receptor envía un ACK con valor N está confirmando que ha recibido todo hasta el byte N-1.

Campo Función
Número de secuencia Marca el primer byte transportado en el segmento.
Número de ACK Próximo byte esperado; confirma implícitamente los anteriores.
Ventana Indica cuántos bytes adicionales pueden enviarse sin recibir más ACK.

Cuando aparecen ACK duplicados es porque el receptor está esperando un segmento faltante; TCP usa esta señal para disparar retransmisiones rápidas.

9.3 Segmentación vs. fragmentación IP

No hay que confundir la segmentación voluntaria de TCP con la fragmentación involuntaria de la capa IP. La primera ocurre en el host de origen y conserva los números de secuencia; la segunda sucede cuando un router encuentra un MTU menor al esperado y divide el paquete IP, lo que puede generar pérdidas costosas.

  • Segmentación (TCP): controlada, respeta el MSS y simplifica el reensamblado.
  • Fragmentación (IP): puede ocurrir en múltiples hops, no reenvía información de transporte completa y complica la recuperación ante pérdidas.

Por eso es recomendable ajustar el MSS y utilizar mecanismos como Path MTU Discovery para evitar fragmentar en la red.

9.4 Reensamblado y detección de orden

El receptor almacena temporalmente los segmentos que llegan fuera de orden. Si recibe bytes 0-999 y luego 2000-2999, guardará el hueco 1000-1999 hasta que aparezca el segmento faltante.

Cuando el hueco se completa, el receptor entrega los datos a la aplicación respetando la secuencia original. Este proceso requiere buffers suficientes, por lo que el control de flujo anunciado en la ventana es tan importante.

9.5 Análisis de un flujo TCP en Wireshark

En Wireshark se pueden seguir los números de secuencia activando las columnas SEQ/ACK Analysis. Un ejemplo común:

  1. Handshake (SYN, SYN-ACK, ACK) con los ISN iniciales.
  2. Segmentos de datos numerados en bloques de 1460 bytes.
  3. ACK duplicados cuando un segmento se pierde; aparecen resaltados en amarillo.
  4. Retransmisión y posterior reanudación del conteo normal.

Los gráficos Sequence vs. Time muestran una línea ascendente que se aplana cuando la red frena la entrega. Detectar pendientes rotas ayuda a diagnosticar saturación o limitaciones de ventana.

9.6 Simulación en Python

El siguiente código divide un mensaje en segmentos, los mezcla para simular entregas fuera de orden y luego los reconstruye usando los números de secuencia:

Numeración y reensamblado

import random

def segmentar(texto, mss=12):
    segmentos = []
    for i in range(0, len(texto), mss):
        segmentos.append((i, texto[i:i + mss]))
    return segmentos

def desordenar(segmentos):
    mezcla = segmentos[:]
    random.shuffle(mezcla)
    return mezcla

def reensamblar(segmentos):
    segmentos_ordenados = sorted(segmentos, key=lambda item: item[0])
    return "".join(parte for _, parte in segmentos_ordenados)

mensaje = "TCP asegura que el receptor reconstruya los bytes exactamente."
partes = segmentar(mensaje)
print("Segmentos originales:", partes)
mezcla = desordenar(partes)
print("Segmentos fuera de orden:", mezcla)
print("Mensaje reconstruido:", reensamblar(mezcla))

Este ejemplo sencillo ilustra la función de los números de secuencia: aun cuando los segmentos llegan mezclados, basta con ordenarlos por su desplazamiento inicial para recuperar el mensaje.

9.7 Herramientas de apoyo

Además de Wireshark, existen utilidades para inspeccionar segmentación sin interfaz gráfica:

  • tshark: permite filtrar por números de secuencia desde la línea de comandos.
  • tcpdump: muestra los SEQ/ACK en tiempo real para conexiones específicas.
  • capinfos: resume el tamaño promedio de los segmentos capturados.

Registrar estos datos en un flujo de CI/CD facilita detectar regresiones cuando un cambio en la aplicación altera la forma en que envía los datos.

9.8 Buenas prácticas

  • Ajustar el MSS para evitar fragmentación IP y reducir retransmisiones.
  • Monitorear números de secuencia en servidores de alta carga para identificar huecos recurrentes.
  • Usar herramientas de captura al desplegar nuevas versiones para comprobar que la segmentación sigue siendo eficiente.

9.9 Cierre

La segmentación y la numeración son la base de la confiabilidad en TCP. Sin ellas, cada aplicación debería reinventar su propio mecanismo para dividir datos y confirmar recepciones. Al dominar estos conceptos podrás interpretar cualquier captura de red, diagnosticar retransmisiones y optimizar el desempeño extremo a extremo.