¿Se pueden dividir los paquetes TCP y UDP en pedazos?

41

¿Pueden los paquetes TCP llegar al receptor por piezas?

Por ejemplo, si envío 20 bytes usando el protocolo TCP, ¿puedo estar 100% seguro de que recibiré exactamente 20 bytes a la vez, no 10 bytes y luego otros 10 bytes?

Y la misma pregunta para el protocolo UDP.
Sé que UDP no es confiable y que los paquetes no pueden llegar o llegar en un orden diferente, pero ¿qué pasa con un solo paquete? Si llega, ¿puedo estar seguro de que es un paquete completo, no una pieza?

iamnp
fuente
77
Un punto de aclaración: se llama segmento TCP y datagrama UDP. No son paquetes. TCP = Segmento, UDP = Datagrama, IP = Paquete, Ethernet = Marco, En todas las otras capas (AFAIK) solo se les llama PDU (Unidades de datos de protocolo).
joeqwerty

Respuestas:

33

¿Pueden los paquetes TCP llegar al receptor por partes?

Sí. IP admite la fragmentación, aunque TCP generalmente intenta determinar la ruta MTU y mantener sus paquetes más pequeños que eso por razones de rendimiento. La fragmentación aumenta la tasa de pérdida de datagramas catastróficamente. Si una ruta tiene una tasa de pérdida de paquetes del 10%, fragmentar un datagrama en dos paquetes hace que la tasa de pérdida de datagramas sea casi del 20%. (Si se pierde cualquiera de los paquetes, se pierde el datagrama).

Sin embargo, no tiene que preocuparse por esto, y tampoco la capa TCP. La capa IP vuelve a ensamblar los paquetes en datagramas completos.

Por ejemplo: si envío 20 bytes usando el protocolo TCP, ¿puedo estar 100% seguro de que recibiré exactamente 20 bytes a la vez, no 10 bytes y luego otros 10 bytes?

No, pero eso no tiene nada que ver con los paquetes. TCP es, fundamentalmente, un protocolo de flujo de bytes que no conserva los límites de los mensajes de la aplicación.

Y la misma pregunta para el protocolo UDP. Sé que UDP no es confiable y que los paquetes no pueden llegar o llegar en un orden diferente,

Lo mismo es cierto para TCP. Los paquetes son paquetes. La diferencia es que TCP tiene reintentos y reordenamientos integrados en el protocolo, mientras que UDP no.

pero que pasa con 1 paquete? Si llega, ¿puedo estar seguro de que es un paquete completo, no una pieza?

No, pero ese no es tu problema. El protocolo UDP maneja el reensamblaje de datagramas. Eso es parte de su trabajo. (En realidad, el protocolo IP hace esto para el protocolo UDP, por lo que UDP lo hace simplemente por capas sobre IP). Si un datagrama se divide en dos paquetes, el protocolo IP lo volverá a ensamblar para el protocolo UDP, por lo que verá los datos completos.

David Schwartz
fuente
10
Puede valer la pena aclarar el último bit para los lectores novatos: verá los datos completos del datagrama en cuestión . Si alguno de los paquetes divididos se pierde, el datagrama se pierde y la capa UDP nunca lo sabrá. Siempre que se reciban todos los paquetes en el datagrama, se ensamblarán en la capa IP y luego se pasarán a la capa UDP. Esto no excluye la posibilidad de que falten "fragmentos" en el flujo de datos. No para ser un pedante, pero cuando estaba aprendiendo estas cosas no supe la diferencia entre el fragmento de IP y la pérdida de UDP hasta el segundo o tercer pase a través del libro de texto.
Justin ᚅᚔᚈᚄᚒᚔ
20

No puedes estar seguro de que realmente lleguen físicamente de una vez. Las capas de enlace de datos debajo de TCP / UDP pueden dividir su paquete si así lo desean. Especialmente si envía datos a través de Internet o cualquier red fuera de su control, es difícil predecirlo.

Pero no importa si los datos llegan en un paquete o en varios paquetes al receptor. El sistema operativo debe abstraer la concatenación de estos paquetes, por lo que para su aplicación todavía parece que todo llegó de una vez. Por lo tanto, a menos que sea un pirata informático del núcleo, en la mayoría de los casos no debe preocuparse si estos datos se transfieren en uno o varios paquetes.

Para UDP, el sistema operativo también hará algo de abstracción, por lo que la aplicación que recibe los datos no tiene que saber en cuántos paquetes se han transmitido los datos. Pero la diferencia con TCP es que no hay garantía de que los datos lleguen realmente. También es posible que los datos se dividan en múltiples paquetes, y algunos lleguen y otros no. Para la aplicación receptora, de todos modos, parece una secuencia de datos, sin importar si está completa o no.

repetición
fuente
¿El controlador de la tarjeta de red no se encarga de volver a ensamblar los paquetes, no el núcleo?
bluehallu
2
@Hallucynogenyc: a menos que las cosas hayan cambiado, el protocolo de Internet está diseñado para permitir que los paquetes de más de 576 bytes se dividan en cualquier punto de su viaje, pero no espera nada más que el destinatario final para recombinarlos. Creo que la idea es que el uso de paquetes más grandes fue en la mayoría de los casos un esfuerzo para reducir la sobrecarga; una vez que un paquete se ha dividido en algún momento de su viaje, ya se ha incurrido en la sobrecarga, por lo que se recombina antes de que el destinatario final no pueda ayudar en nada, y puede doler si tiene que volver a dividirse.
supercat
Creo que si bien cualquier paquete que tenga más de 576 bytes puede dividirse, los paquetes que están por debajo de ese tamaño pueden no hacerlo; Los sistemas integrados que no pueden manejar paquetes divididos deben evitar pedir algo más grande que eso.
supercat
1
@ mauro.stettler: he escrito una pila TCP en "metal desnudo" (escribiendo el código para hablar directamente con varios chips de interfaz de red). Para el hardware que se comunica con un enlace con un límite de 576 bytes para dividir paquetes más largos es simple. El reensamblaje de paquetes es mucho más complicado, especialmente porque uno puede recibir piezas de muchos paquetes diferentes antes de que cualquiera de ellos se reciba por completo.
supercat
Existe la esperanza de que no se dividirá para pequeñas cargas útiles (alrededor de 10 o 20 bytes deberían estar bien), porque hay un "tamaño máximo garantizado" requerido de cada salto para paquetes IP en ipv4: al menos 68 bytes (incluyendo Encabezados IP, y sin contar encabezados de nivel inferior). vea la primera tabla en es.wikipedia.org/wiki/Maximum_transmission_unit . Diferente de los 576 bytes de tamaño mínimo requerido de los HOSTS (es decir, el origen o el final de la transmisión, no todos los saltos intermedios). Y cuidado: la carga útil es aún más baja (ya que los encabezados de cada capa ocupan algo de espacio).
Olivier Dulac
14

Ejemplos. Los bloques de caracteres contiguos corresponden a las llamadas send ():

TCP:

Send: AA BBBB CCC DDDDDD E         Recv: A ABB B BCC CDDD DDDE

Todos los datos enviados se reciben en orden, pero no necesariamente en los mismos fragmentos.

UDP:

Send: AA BBBB CCC DDDDDD E         Recv: CCC AA E

Los datos no están necesariamente en el mismo orden y no se reciben necesariamente, pero los mensajes se conservan en su totalidad.

Jim Cote
fuente
5

Por ejemplo: si envío 20 bytes usando el protocolo TCP, ¿puedo estar 100% seguro de que recibiré exactamente 20 bytes a la vez, no 10 bytes y luego otros 10 bytes?

No, TCP es un protocolo de flujo, mantiene los datos en orden pero no los agrupa por mensaje. Por otro lado, UDP está orientado a mensajes, pero no es confiable. SCTP tiene lo mejor de ambos mundos, pero no se puede usar de forma nativa porque los NAT rompen Internet.

Changaco
fuente
1

Hay cierta seguridad de que si envía 20 bytes al comienzo de una secuencia TCP, no llegará como dos piezas de 10 bytes. Esto se debe a que la pila TCP no enviará segmentos tan pequeños: hay un tamaño mínimo de MTU. Sin embargo, si el envío está en algún lugar en medio de una transmisión, todas las apuestas están desactivadas. Podría ser que su pila de protocolos tome 10 bytes de los datos para llenar un segmento y enviarlo, y luego los siguientes diez bytes van a otro segmento.

Su pila de protocolos divide los datos en fragmentos y los coloca en una cola. Los tamaños de los fragmentos se basan en la ruta MTU. Si realiza una operación de envío, y todavía hay datos en cola pendientes, la pila de protocolos normalmente mirará el segmento que está en la cola de la cola y verá si hay espacio en ese segmento para agregar más datos. La habitación puede ser tan pequeña como un byte, por lo que incluso un envío de dos bytes se puede dividir en dos.

Por otro lado, la segmentación de datos significa que puede haber lecturas parciales. Una operación de recepción puede potencialmente despertarse y obtener datos cuando llega tan solo un segmento. En la API de sockets ampliamente implementada, una llamada de recepción puede solicitar 20 bytes, pero podría regresar con 10. Por supuesto, se puede construir una capa de almacenamiento en búfer que se bloqueará hasta que se reciban 20 bytes o se rompa la conexión. En el mundo POSIX, esa API puede ser la secuencia de E / S estándar: puede usar fdopenun descriptor de socket para obtener una FILE *secuencia, y puede usarla freadpara llenar un búfer de modo que la solicitud completa se satisfaga con tantas readllamadas como sea necesario .

Los datagramas UDP enmarcan los datos. Cada llamada de envío genera un datagrama (pero vea más abajo sobre el descorche). El otro lado recibe un datagrama completo (y, en la API del socket, debe especificar un búfer lo suficientemente grande como para contenerlo, de lo contrario, el datagrama se truncará). Los grandes datagramas se fragmentan por fragmentación de IP y se vuelven a ensamblar de forma transparente para las aplicaciones. Si falta algún fragmento, se pierde todo el datagrama; no hay forma de leer datos parciales en esa situación.

Existen extensiones a la interfaz que permiten múltiples operaciones para especificar un solo datagrama. En Linux, se puede "tapar" un socket (evitar que se envíe). Mientras se tapa, los datos escritos se ensamblan en una sola unidad. Luego, cuando el zócalo está "descorchado", se puede enviar un solo datagrama.

Kaz
fuente
esto es falso: si uno envía un paquete con una carga útil de 10 o 20 bytes, esto generará 1 paquete, y (como dije anteriormente), si usa ipv4, debería, incluso al agregar todos los encabezados de las otras capas de protocolo, encajar dentro de 68 bytes, asegurando así que pasa por todos los saltos en 1 paquete. La pila de TCP no (como se insinúa en su primer párrafo) "esperará hasta que se llene el mtu (es decir, agregue varios paquetes para hacer uno del tamaño adecuado)" para enviar un paquete! ... Este comportamiento rompería muchas cosas ( incluso si esos "fragmentos" fueron enviados desde y al mismo par de hosts)
Olivier Dulac
@ OlivierDulac: Eso es incorrecto. TCP generalmente genera paquetes según sea necesario, tratando de optimizar el uso de la red, por lo que 20 bytes podrían terminar en dos paquetes diferentes como lo explica Kaz. Esto se puede controlar utilizando la opción de socket TCP_NODELAY , que deshabilita el algoritmo de Nagles que distribuye bytes a paquetes, si su aplicación necesita una red TCP más rápida. Además, 68 bytes no es el estándar de facto para la longitud del paquete: 1500 bytes es un valor predeterminado más habitual (esto realmente varía entre las redes).
jjmontes