Question

J'ai un tableau d'octets que je lis depuis un NetworkStream. Les deux premiers octets indiquent la longueur du paquet qui suit, puis le paquet est lu dans un tableau d'octets de cette longueur. Les données dans lesquelles j'ai besoin de lire à partir du tableau NetworkStream / byte ont quelques chaînes, c'est-à-dire des données de longueur variable terminées par des caractères de nouvelle ligne et des champs de largeur fixe tels que bytes et longs. Donc, quelque chose comme ça:

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

Je connais le format du paquet de données (et j'ai son mot à dire), et ce que je dois faire, c'est lire une & "ligne &"; pour chaque valeur de chaîne, mais lit un nombre d'octets fixe pour les octets et les longs. Jusqu'ici, ma solution proposée consiste à utiliser une boucle while pour lire des octets dans un tableau d'octets temporaire jusqu'à l'apparition d'un caractère de nouvelle ligne. Ensuite, convertissez les octets en chaîne. Cela me semble ridicule, mais je ne vois pas d'autre moyen évident. Je réalise que je pourrais utiliser StreamReader.ReadLine() mais cela impliquerait un autre flux et j’ai déjà un NetworkStream. Mais si c'est la meilleure solution, je vais essayer.

L’autre option envisagée est de demander à mon équipe backend d’écrire un octet ou deux pour les longueurs de ces valeurs de chaîne afin que je puisse lire la longueur puis lire la chaîne en fonction de la longueur spécifiée.

Ainsi, comme vous pouvez le constater, j’ai quelques options sur la façon de procéder, et j'aimerais connaître votre avis sur ce que vous envisageriez comme le meilleur moyen de procéder. Voici le code que j'ai en ce moment pour lire l'intégralité du paquet sous forme de chaîne. La prochaine étape consiste à décomposer les différents champs du paquet et à effectuer le travail de programmation nécessaire, à savoir la création d’objets, la mise à jour de l’UI, etc. en fonction des données du paquet.

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);
}
Était-ce utile?

La solution

Personnellement je le ferais

  1. Mettez un Int16 au début de la cordes, donc vous savez combien de temps ils vont être, et
  2. Utilisez la classe IO.BinaryReader pour faire la lecture, il va & "lire &", ints, des chaînes, des caractères, etc. dans une variable, par ex. BinReader.ReadInt16 () lira deux octets, renverra l'int16 qu'ils représentent et déplacera deux octets dans le flux

J'espère que cela vous aidera.

P.S. Soyez prudent en utilisant la méthode ReadString, car elle suppose que la chaîne est complétée par des entiers personnalisés à 7 bits, c’est-à-dire qu’elle a été écrite par la classe BinaryWriter. Ce qui suit est extrait de cette CodeGuru post

  

La classe BinaryWriter a deux méthodes   pour écrire des chaînes: le surchargé   Méthode Write () et WriteString ()   méthode. Le premier écrit la chaîne   comme un flux d'octets selon le   l'encodage de la classe utilise. le   WriteString () utilise également le   codage spécifié, mais préfixes   le flux d'octets de la chaîne avec le   longueur réelle de la chaîne. Tel   les chaînes préfixées sont relues via   BinaryReader.ReadString ().

     

La chose intéressante à propos de la longueur   valorisez le moins d'octets possible   sont utilisés pour tenir cette taille, il est   stocké sous un type appelé 7 bits   nombre entier codé. Si la longueur convient   7 bits, un seul octet est utilisé, s'il est   plus que cela alors le bit haut sur   le premier octet est défini et un second   octet est créé en décalant la valeur   par 7 bits. Ceci est répété avec   octets successifs jusqu'à ce qu'il y ait   assez d'octets pour contenir la valeur. Ce   mécanisme est utilisé pour s'assurer que   la longueur ne devient pas un   portion importante de la taille prise   up par la chaîne sérialisée.   BinaryWriter et BinaryReader ont   méthodes pour lire et écrire 7 bits   entiers codés, mais ils sont   protégé et que vous ne pouvez les utiliser que   si vous dérivez de ces classes.

Autres conseils

Je choisirais des chaînes avec un préfixe de longueur. Votre vie sera beaucoup plus simple, et cela signifie que vous pouvez représenter des chaînes avec des sauts de ligne. Quelques commentaires sur votre code cependant:

  • N'utilisez pas Stream.DataAvailable. Le fait qu’aucune donnée ne soit disponible maintenant ne signifie pas que vous avez lu la fin du flux.
  • Sauf si vous êtes absolument sûr de ne jamais avoir besoin de texte au-delà de ASCII, n'utilisez pas ASCIIEncoding.
  • Ne supposez pas que Stream.Read lira toutes les données que vous lui demandez. Toujours vérifiez la valeur de retour.
  • BinaryReader facilite beaucoup cela (y compris les chaînes avec un préfixe de longueur et une lecture qui boucle jusqu'à ce que vous lisiez ce que vous lui avez demandé)
  • Vous appelez BitConverter.ToUInt16 deux fois sur les mêmes données. Pourquoi?
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top