Pergunta

Eu tenho uma matriz de bytes que eu estou lendo a partir de um NetworkStream. Os dois primeiros bytes dizer o comprimento do pacote que se segue e, em seguida, o pacote é lido em uma matriz de bytes do que o comprimento. Os dados em que preciso para ler a partir da matriz NetworkStream / byte tem algumas cordas, isto é, dados de comprimento variável e terminada por novos caracteres de linha, e uma largura fixa campos como bytes e longos. Então, algo como isto:

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

Eu sei (e ter alguma palavra a dizer em) o formato do pacote de dados que está vindo do outro lado, eo que eu preciso fazer é ler uma "linha" para cada valor da cadeia, mas ler um número fixo de bytes para os bytes e longos. Até agora, a minha solução proposta é a utilização de um circuito de while a ler bytes em uma matriz de byte temperatura até que haja um carácter de nova linha. Em seguida, converter os bytes para uma cadeia. Isto parece kludgy para mim, mas eu não vejo outra maneira óbvia. Eu percebo que eu poderia usar StreamReader.ReadLine() mas que envolveria um outro córrego e eu já tenho um NetworkStream. Mas se essa é a melhor solução, eu vou dar-lhe um tiro.

A outra opção que tenho considerado é ter a minha escrita equipe backend um byte ou dois para comprimentos esses valores string para que eu possa ler o comprimento e, em seguida, ler a cadeia com base no comprimento especificado.

Então, como você pode ver, eu tenho algumas opções de como fazer isto, e eu gostaria que a sua entrada sobre o que você consideraria a melhor maneira de fazê-lo. Aqui está o código que eu tenho agora para leitura em todo o pacote como uma string. O próximo passo é quebrar os vários campos do pacote e fazer o trabalho de programação real que precisa ser feito, a criação de objetos, atualizando UI, etc. com base nos dados no pacote.

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);
}
Foi útil?

Solução

Pessoalmente eu faria

  1. Coloque um Int16 no início do cordas, para que você saiba quanto tempo eles vão ser, e
  2. Use a classe IO.BinaryReader para fazer a leitura, ele vai "ler", ints, cordas, etc caracteres em variável e.g. BinReader.ReadInt16 () irá ler dois bytes, devolver o int16 eles representam, e mover dois bytes em no fluxo

Espero que isso ajude.

P.S. Tenha cuidado ao usar o método ReadString, ele assume a string é prefixado com inteiros costume 7 bits ou seja, que ele foi escrito pela classe BinaryWriter. O seguinte é a partir deste CodeGuru pós

A classe BinaryWriter tem dois métodos para escrever strings: o sobrecarregado Write () método e o WriteString () método. O ex-escreve a string como uma corrente de bytes de acordo com a que codifica a classe é a utilizar. o WriteString () método também utiliza a codificação especificada, mas prefixos fluxo da seqüência de bytes com o comprimento real da string. Tal cordas prefixadas são lidos de volta na via BinaryReader.ReadString ().

A coisa interessante sobre o comprimento valorizar-se que o menor número de bytes possível são usados ??para manter este tamanho, é armazenado como um tipo chamado um 7-bit número inteiro codificado. Se o comprimento se encaixa 7 bits de um único byte é utilizado, se é maior do que isso, então o bit alto em o primeiro byte está definido e um segundo byte é criado pelo desvio do valor por 7 bits. Isto é repetido com sucessivos bytes até há suficiente bytes para armazenar o valor. este mecanismo é usado para se certificar de que o comprimento não se torne um porção significativa do tamanho feita -se pela cadeia serializada. BinaryWriter e BinaryReader têm métodos para ler e escrever 7-bit inteiros codificado, mas são protegido e para que você possa usá-los somente Se você derivar dessas classes.

Outras dicas

Eu iria com cordas prefixo de comprimento. Ele vai fazer a sua vida muito mais simples, e isso significa que você pode representar strings com quebras de linha em alguns comentários sobre o seu código embora:.

  • Não use Stream.DataAvailable. Só porque não há dados disponíveis agora não significa que você já leu o fim do fluxo.
  • A menos que você está absolutamente certo de que você nunca mais vai precisar texto para além ASCII, não use ASCIIEncoding.
  • Não presuma que Stream.Read vai ler todos os dados que você pedir para ele. Sempre verificar o valor de retorno.
  • BinaryReader faz muito isso muito mais fácil (incluindo cordas prefixo de comprimento e uma leitura que voltas até que seja lido o que você pediu que ele)
  • Você está chamando BitConverter.ToUInt16 duas vezes no mesmo dados. Por quê?
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top