2010-03-05 13 views
14

En una aplicación cliente/servidor donde se enviarán datos de texto de distinta longitud entre el cliente y el servidor, ¿cómo debo marcar el final de un paquete que se está enviando? Por ejemplo, cuando el servidor está recibiendo datos de paquete de un cliente, ¿cómo sabe el servidor que el paquete del cliente se ha recibido por completo?¿Cómo debo marcar el final de un paquete TCP?

¿Es más común decirle al servidor la longitud total del paquete que va a recibir antes de los datos o tener algo marcando el final del paquete?

Algunos de los datos enviados tendrán solo unos pocos caracteres y algunos podrían tener miles de caracteres.

+2

Supongo que no le preocupan los paquetes TCP, sino los mensajes a nivel de aplicación dentro de la transmisión TCP, ¿no? –

Respuesta

23

TCP proporciona un flujo continuo de datos. TCP es implementado utilizando paquetes, pero el objetivo de TCP es ocultarlos.

Piense en ello como si fuera una pared sobre la que desea dibujar. La pared está hecha de ladrillos. Los ladrillos se pegan con mortero y se aplica yeso para que la superficie de la pared se vuelva lisa. Los ladrillos son los paquetes de IP, TCP es el yeso.

Así que ahora tiene su túnel TCP enlucido liso, y desea agregar algo de estructura en él. Desea dibujar cuadros, para que sus dibujos se mantengan separados el uno del otro. Esto es lo que quiere hacer: agregar un poco de estructura "administrativa" (recuadros alrededor de los dibujos) a sus datos.

Muchos protocolos utilizan el concepto de packet, que es un conjunto de datos que comienza con un encabezado administrativo de formato fijo. El encabezado contiene suficiente información para decidir dónde termina el paquete; por ejemplo, incluye la longitud del paquete. HTTP lo hace, con un encabezado Content-Length, o (con HTTP/1.1) con la "codificación de transferencia fragmentada" donde los datos se dividen en uno o varios mini-paquetes, cada uno con un encabezado simple que consiste exactamente en una indicación de mini-paquete-longitud .

Otra forma es tener una secuencia de terminador especial que no puede aparecer en "datos normales". Si sus datos son texto, entonces podría usar un byte de valor cero como terminador.

Otra forma es usar datos con terminación propia. Estos son datos estructurados de tal forma que usted puede saber en cualquier momento si se ha alcanzado el final del elemento. Por ejemplo, los datos XML se organizan como pares anidados de marcadores como <foo>...</foo>. Cuando se alcanza el marcador final (</foo>), sabrá que el elemento está terminado.

3

Estructure su paquete de forma que incluya un campo de longitud al principio.

1

Sigue tus señales de HTTP.

Utilice una secuencia de caracteres de terminador, o especifique una longitud en algún lugar del encabezado del mensaje, o use una combinación inteligente de ambos.

Como hace HTTP: los encabezados terminan con CR-LF-CR-LF. Si hay datos más allá de los encabezados, la longitud de los datos está en uno de los encabezados.

+1

Las secuencias del terminador se vuelven complicadas cuando debe enviar datos arbitrarios, porque los datos pueden (por coincidencia) contener la secuencia del terminador, lo que podría confundir al analizador receptor. Puede evitar eso implementando algún tipo de protocolo de código de escape, pero en ese punto las cosas son más complicadas que simplemente enviar primero un campo de longitud, por lo que también podría enviar primero el campo de longitud y mantener las cosas simples. –

2

Si el emisor conoce la longitud, el emisor debe indicar la longitud por adelantado como un campo de tamaño fijo, seguido de los datos de tamaño variable.

La ventaja frente a un marcador de cola es que el receptor puede optimizar la cantidad esperada de datos, p. asigna un buffer del tamaño correcto. Por ejemplo, el almacenamiento a través de protocolos TCP/IP tiene el mismo problema sobre TCP/IP que usted. En esos casos, los encabezados proporcionan la longitud de los datos esperados posteriormente.

Más adelante en el camino, puede encontrar otros bits para poner en su "encabezado". Se alegrará de tener alguna estructura para hacer crecer su propio protocolo de capa 5.

1

Si te sientes particularmente audaz, puedes buscar usando sockets SCTP en lugar de sockets TCP.

1

Tenga cuidado con la basura si codifica la longitud al principio. Por ejemplo, si utiliza 4 bytes binarios para la longitud y una sonda externa envía una solicitud HTTP, es probable que termine con un gran número y esperando por siempre (sin mencionar la asignación de un búfer que podría bloquear su programa). Envío la longitud dos veces cada uno a través de una función diferente y los comparo (por ejemplo, ~ len y len xor 0x139AF321). También debe establecer un máximo en caso de que alguien intente bloquear su programa activamente. Si obtengo una mala longitud, simplemente cierro la conexión.

Esto está por encima de un HMAC si su tráfico está encriptado.

Cuestiones relacionadas