2010-02-16 12 views
7

Imagine que usted y yo estamos enviando una frase bastante larga (digamos, 1024000 bytes) a través de TCP.¿Debo insertar manualmente la información de tamaño de datos en una transferencia TCP?

Si se escribe una oración 1024000 bytes para mí, en realidad se utiliza para escribir NetworkStream esos bytes en.

Cuando recibo, debería saber de antemano el tamaño de la sentencia que envió?

En caso negativo, ¿cómo puedo verificar cuándo debo detener la transmisión de stream.read?

En caso afirmativo, ¿el programa debe tener instalaciones que incluyan el tamaño de los datos en el encabezado de los datos? ¿Entonces recibo 4 bytes primero para ver cuántos totales debo leer?

¿.Net tiene algo para incrustar automáticamente el tamaño de datos en la transferencia?

+0

Bien, ¿podría alguien decirme cómo agregar NULL al final de la transmisión? – Jack

Respuesta

4

Ni .NET ni el protocolo TCP tienen algo incorporado para definir el tamaño del mensaje que se adelantará. El protocolo TCP solo especifica que todos los datos se transferirán al punto final receptor (o al menos que se empleará el mejor esfuerzo para hacerlo).

Usted es el único responsable de definir una forma de que el receptor sepa la cantidad de datos que debe leer. Los detalles de cómo lo hace son, como han señalado otros, dependientes de la naturaleza de lo que está transfiriendo: podría enviar la longitud primero como usted mencionó, podría codificar secuencias especiales llamadas terminadores, podría usar fragmentos de datos predefinidos entonces todos los mensajes tienen el mismo tamaño, etc.

EDITAR

Esto comenzó como un comentario, pero hay más a él que se ajusta a ese límite.

Para complemento NULL a la corriente significa simplemente añadiendo un carácter que tiene el valor binario 0 (que no debe confundirse con el carácter 0). Dependiendo de la codificación que está utilizando para su transferencia (es decir, ASCII, UTF-8, UTF-16, etc.) que puede traducirse en el envío de uno o más bytes 0, pero si está utilizando la traducción adecuada, simplemente debe poner algo como \0 en tu cadena. He aquí un ejemplo:

string textToSend = "This is a NULL Terminated text\0"; 
byte[] bufferToSend = Encoding.UTF8Encoding.GetBytes(textToSend); 

Por supuesto, todo lo anterior supone que todo el resto de los datos que va a enviar no contiene otros valores NULL. Eso significa que es texto, y no datos binarios arbitrarios (como el contenido de un archivo). ¡Eso es muy importante! De lo contrario, no puede usar NULL como terminador de mensajes y debe crear otro esquema.

+0

¿podría decirme cómo agregar NULL al final de la transmisión? – Jack

+0

Sí. Dicho de otra forma, un socket TCP proporciona una corriente confiable de octetos. Cualquier estructura o límite debe ser impuesto por las aplicaciones de envío y recepción. –

+0

La desventaja de esto es que siempre puede solicitar un solo byte de la transmisión si desea evitar leer más allá del final del mensaje. Esto puede volverse bastante lento. – x4u

1

Cuando recibo, ¿debo saber antes sobre el tamaño de la oración que enviaste?

Eso puede ser útil (para cosas como barras de progreso de representación), pero no es necesariamente obligatorio.

En caso negativo, ¿cómo puedo comprobar cuándo debo detener la transmisión de stream.read?

El contenido de la secuencia define esto. Por ejemplo, muchos mensajes codifican cierta información que indica que este mensaje ha finalizado (por ejemplo, un byte nulo para representar el final de una cadena, o </html> para representar el final de un documento HTML).

1

Hay dos formas de hacerlo, una es la que describió (colocar el tamaño del mensaje en el encabezado) y otra es poner algún tipo de marcador de terminación en la secuencia. Por ejemplo, si se garantiza que su mensaje no tiene incrustados NUL caracteres, puede terminar con NUL.

0

Dado que TCP es un protocolo confiable, puede estructurar su protocolo para indicar el número de bytes que viene o usar algún tipo de terminador para indicar el final de la transmisión. Si usa UDP, que no se garantiza que sea confiable, sería mucho más importante construir un protocolo que resista bytes caídos o indicar cuántos bytes se esperan (y tener un mecanismo de retransmisión) ya que el paquete que contiene la terminación puede perderse Los tiempos y tiempos de espera máximos de transmisión de datos también pueden ser útiles, pero solo si puede determinar un máximo razonable.

1

Si conoce o puede averiguar fácilmente la duración total del mensaje, le sugiero que lo transmita con antelación. Si es imposible o muy costoso determinarlo, puede usar algo similar al chunked transfer encoding en HTTP.

2

En general, es mejor utilizar un encabezado con el tamaño de datos que un carácter de terminación. El método de carácter de terminación es susceptible a un ataque de denegación de servicio. Puedo seguir enviando datos a su servicio, y mientras no incluya el terminador, necesita seguir procesando (y posiblemente asignando memoria) hasta que se cuelgue.

Usando un encabezado que contiene el tamaño total, si una transmisión es demasiado grande para que la maneje, puede ignorarla o enviar un error. Si una parte maliciosa intenta enviar más datos de los declarados en el encabezado, notará un encabezado dañado al comienzo de la siguiente transmisión y lo ignorará.

+0

buen punto ... pero eso supone una implementación ingenua del receptor. puede, y debe, tener ciertos límites con la cantidad de datos que recibe y procesa, que pueden determinarse arbitrariamente en función de los tamaños típicos de datos que la aplicación generalmente espera –

1

El punto principal es que con TCP no hay correspondencia entre el número y el tamaño de las escrituras de socket en el lado de la transmisión con el número/tamaño de las lecturas de socket en el lado del receptor.

Si la secuencia de datos tiene algún tipo de estructura, tendrá que agregar algún tipo de meta/envoltura de datos alrededor de la carga útil.

Cada vez que he tenido que resolver este problema que he utilizado una combinación de:

a) utilizar un número mágico para indicar el inicio o el final de su msg de datos (o ambos)

b) utilizar una suma de comprobación al final del mensaje para verificar que el contenido sea correcto (sé que TCP realiza la verificación de error & retransmisión pero la suma de comprobación es útil en el caso en que el receptor detecta una ocurrencia incidental del número/secuencia mágica de inicio/fin en la secuencia)

c) use un campo de longitud después del número mágico inicial (Siempre que el lado transmisor conoce la longitud de los datos antes de que comience transmisión)

Hoever antes de ir bricolaje tienen un buen vistazo a lo que los protocolos de nivel superior libs se implementan para el lenguaje/plataforma que está utilizando. NetworkStream? es esa API/MFC de Windows o algo así.

Por ejemplo, recientemente tuve que configurar un sistema cliente/servidor.La funcionalidad del servidor & del cliente ya estaba escrita en python, por lo que simplemente usar Python xmlrpclib/server hizo que fuera completamente sencillo unir los dos programas, literalmente copié el ejemplo y terminé en 30 minutos. ¡Si hubiera codificado algún protocolo de fabricación yo mismo directamente en tcp, hubieran sido 5 días!

0

Mi respuesta sería no. Especialmente para grandes conjuntos de datos. La razón es que enviar el tamaño primero agrega latencia en su sistema.

Si desea enviar el tamaño primero, debe calcular la respuesta completa antes de comenzar a enviarlo.

Por otro lado, si utiliza un marcador de finalización, puede comenzar a enviar los primeros bits de datos tan pronto como estén listos, al calcular los siguientes datos.

0

Es posible que también desee investigar las clases BinaryReader/BinaryWriter que se pueden encerrar en cualquier secuencia, TCP u otra.

Éstos son compatibles, entre otras funciones, con la lectura/escritura de cadenas (en una codificación de su elección) teniendo en cuenta también incluir la longitud de la cadena.

Cuestiones relacionadas