2012-09-26 14 views
6

Acabo de leer un artículo que dice que TCPClient.Read() puede no obtener todos los bytes enviados en una sola lectura. ¿Cómo cuentas esto?cómo se tiene en cuenta cuando TCP no obtiene todos los bytes en uno leído

Por ejemplo, el servidor puede escribir una cadena en la secuencia tcp. El cliente lee la mitad de los bytes de la cadena y luego lee la otra mitad en otra llamada de lectura.

¿cómo sabes cuando necesitas combinar las matrices de bytes recibidas en ambas llamadas?

Respuesta

16

¿cómo saber cuándo debe combinar las matrices de bytes recibidas en ambas llamadas?

Debe decidir esto en el nivel de protocolo. Hay cuatro modelos comunes:

  • Cerrar-en-terminar: cada lado solo puede enviar un solo "mensaje" por conexión. Después de enviar el mensaje, cierran el lado de envío del socket. El lado receptor continúa leyendo hasta que llega al final de la transmisión.
  • Prefijo de longitud: antes de cada mensaje, incluya el número de bytes en el mensaje. Esto podría ser en un formato de longitud fija (por ejemplo, siempre de 4 bytes) o en algún formato comprimido (por ejemplo, 7 bits de datos de tamaño por byte, bit superior configurado para el byte final de datos de tamaño). Luego está el mensaje en sí. El código de recepción leerá el tamaño, luego leerá muchos bytes.
  • Chunking: como el prefijo de longitud, pero en trozos más pequeños. Cada fragmento tiene un prefijo de longitud, con un fragmento final que indica "fin del mensaje"
  • Señal de fin de mensaje: siga leyendo hasta que vea el terminador del mensaje. Esto puede ser molesto si el mensaje debe poder incluir datos arbitrarios, ya que deberá incluir un mecanismo de escape para representar los datos del terminador dentro del mensaje.

Además, con menor frecuencia, existen protocolos que cada mensaje es siempre un tamaño determinado - en cuyo caso sólo tiene que seguir adelante hasta que haya leído que muchos datos.

En todos estos casos, básicamente es necesario realizar un bucle, leer datos en una especie de búfer hasta que tenga suficiente, sin importar cómo lo determine. Debería siempre usar el valor de retorno de Read para notar cuántos bytes leyó realmente, y siempre comprobar si es 0, en cuyo caso ha llegado al final de la secuencia.

También tenga en cuenta que esto no solo afecta a las transmisiones de red: para cualquier cosa que no sea una MemoryStream local (que siempre leerá la cantidad de datos que pida de una vez, si está en la transmisión), debería supongamos que los datos solo estarán disponibles en el transcurso de múltiples llamadas.

+0

o haga su propio protocolo: D – EaterOfCode

+0

O podría tener un protocolo de longitud fija donde conozca la longitud de los mensajes por adelantado. Sin embargo, no puedo pensar en un ejemplo útil de la parte superior de mi cabeza :( – NPSF3000

+0

@EaterOfCorpses: estas son opciones * dentro de * un protocolo. Cómo detectar el final de un mensaje es solo una parte del protocolo. –

-1

Debe llamar al read() en un bucle. La condición de ese ciclo verificará si todavía hay datos disponibles para leer.

+3

Eso es solo válido si la conexión va a terminar por el lado de envío después de que el mensaje ha sido enviado. No funciona si quiere poner varios mensajes en la misma conexión. –

+0

Oh. No lo sabía Gracias. – Paul

+1

Existen solo dos formas de "verificar" si todavía hay datos para leer ". Una de ellas es verificar EOS, que no es válido como @JonSkeet ha señalado anteriormente. La otra es llamar a 'available()', aka 'FIO_NREAD', que simplemente te dice cuántos bytes ya han llegado en el búfer de recepción de socket y se pueden leer sin bloquear: no te dice cuántos datos quedan * en la corriente, * porque no sabe. Nadie puede saber El remitente podría seguir enviando datos para siempre. – EJP

-3

Eso es un poco difícil de responder, porque nunca se sabe cuándo llegarán los datos, y es por eso que generalmente uso un hilo para recibir datos en mi programa de chat. Sin embargo, usted debería ser capaz de usar algo similar a esto:

do{ 
    numberOfBytesRead = myNetworkStream.Read(myReadBuffer, 
               0, 
               myReadBuffer.Length); 

    myCompleteMessage.AppendFormat("{0}", 
     Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead)); 

    } 
    while(myNetworkStream.DataAvailable); 

Mira esta source!

+4

Definitivamente * definitivamente * no. Eso se detendrá tan pronto como los datos no estén disponibles de inmediato, de modo que si un paquete se retrasa, terminará con la mitad de los datos. (También es solo ASCII, que casi nunca es una buena idea en estos días.) Incluso si 'DataAvailable' bloqueado, usted estaría limitado a un solo mensaje en una conexión. Este es el código * malo *. –

+1

Esta es una buena información, incluso si está mal. Es un 'cómo no hacerlo' –

Cuestiones relacionadas