Pregunta

Tengo una matriz de bytes que estoy leyendo desde un NetworkStream. Los primeros dos bytes indican la longitud del paquete que sigue y luego el paquete se lee en una matriz de bytes de esa longitud. Los datos que necesito leer de la matriz NetworkStream / byte tienen algunas cadenas, es decir, datos de longitud variable terminados en nuevos caracteres de línea y algunos campos de ancho fijo como bytes y longitudes. Entonces, algo como esto:

// I would have delimited these for clarity but I didn't want
// to imply that the stream was delimited because it's not.
StringbyteStringStringbytebytebytelonglongbytelonglong

Sé (y tengo algo que decir) el formato del paquete de datos que se está cruzando, y lo que necesito hacer es leer una & "línea &"; para cada valor de cadena, pero lea un número fijo de bytes para los bytes y longs. Hasta ahora, mi solución propuesta es usar un bucle while para leer bytes en una matriz de bytes temporal hasta que haya un carácter de nueva línea. Luego, convierta los bytes en una cadena. Esto me parece torpe, pero no veo otra forma obvia. Me doy cuenta de que podría usar StreamReader.ReadLine() pero eso implicaría otra transmisión y ya tengo un NetworkStream. Pero si esa es la mejor solución, lo intentaré.

La otra opción que he considerado es hacer que mi equipo de fondo escriba un byte o dos para las longitudes de esos valores de cadena para que pueda leer la longitud y luego leer la cadena en función de la longitud especificada.

Entonces, como puede ver, tengo algunas opciones sobre cómo hacer esto, y me gustaría su opinión sobre cuál consideraría la mejor manera de hacerlo. Aquí está el código que tengo ahora para leer en todo el paquete como una cadena. El siguiente paso es dividir los diversos campos del paquete y hacer el trabajo de programación real que se necesita hacer, crear objetos, actualizar la interfaz de usuario, etc. en función de los datos en el paquete.

string line = null;  
while (stream.DataAvailable)
{  
    //Get the packet length;  
    UInt16 packetLength = 0;  
    header = new byte[2];  
    stream.Read(header, 0, 2);  
    // Need to reverse the header array for BitConverter class if architecture is little endian.  
    if (BitConverter.IsLittleEndian)
        Array.Reverse(header);  
    packetLength = BitConverter.ToUInt16(header,0);

    buffer = new byte[packetLength];
    stream.Read(buffer, 0, BitConverter.ToUInt16(header, 0));
    line = System.Text.ASCIIEncoding.ASCII.GetString(buffer);
    Console.WriteLine(line);
}
¿Fue útil?

Solución

Personalmente lo haría

  1. Pon un Int16 al comienzo del cuerdas, para que sepas cuánto tiempo van a ser, y
  2. Utilice la clase IO.BinaryReader para hacer la lectura, & "; leer &"; ints, cadenas, caracteres, etc. en variables, p. ej. BinReader.ReadInt16 () leerá dos bytes, devolverá el int16 que representan y moverá dos bytes en la secuencia

Espero que esto ayude.

P.S. Tenga cuidado al usar el método ReadString, se supone que la cadena se antepone con enteros personalizados de 7 bits, es decir, que fue escrita por la clase BinaryWriter. Lo siguiente es de esta publicación CodeGuru

  

La clase BinaryWriter tiene dos métodos   para escribir cadenas: el sobrecargado   Método Write () y WriteString ()   método. El primero escribe la cadena   como una secuencia de bytes de acuerdo con el   codificando la clase está utilizando. los   El método WriteString () también utiliza el   codificación especificada, pero tiene prefijos   la secuencia de bytes de la cadena con el   longitud real de la cuerda. Tal   las cadenas prefijadas se vuelven a leer a través de   BinaryReader.ReadString ().

     

Lo interesante de la longitud   valorarlo tan pocos bytes como sea posible   se utilizan para mantener este tamaño, es   almacenado como un tipo llamado de 7 bits   entero codificado Si la longitud cabe   7 bits se utiliza un solo byte, si es   mayor que esto, entonces el bit alto en   se establece el primer byte y un segundo   byte se crea cambiando el valor   por 7 bits. Esto se repite con   bytes sucesivos hasta que haya   suficientes bytes para contener el valor. Esta   mecanismo se utiliza para asegurarse de que   la longitud no se convierte en un   porción significativa del tamaño tomado   por la cadena serializada.   BinaryWriter y BinaryReader tienen   métodos para leer y escribir de 7 bits   enteros codificados, pero son   protegido y para que solo puedas usarlos   si deriva de estas clases.

Otros consejos

Iría con cadenas de longitud prefijada. Hará su vida mucho más simple, y significa que puede representar cadenas con saltos de línea. Sin embargo, algunos comentarios sobre su código:

  • No use Stream.DataAvailable. El hecho de que no haya datos disponibles ahora no significa que haya leído el final de la transmisión.
  • A menos que esté absolutamente seguro de que nunca necesitará texto más allá de ASCII, no use ASCIIEncoding.
  • No asumas que Stream.Read leerá todos los datos que le pidas. Siempre verifique el valor de retorno.
  • BinaryReader hace que todo esto sea mucho más fácil (incluidas las cadenas con prefijo de longitud y una lectura que se repite hasta que se lee lo que le pediste)
  • Estás llamando a BitConverter.ToUInt16 dos veces con los mismos datos. ¿Por qué?
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top