Question

J'envoyer et recevoir des données binaires vers / depuis un dispositif dans des paquets (64 octets). Les données ont un format spécifique, dont certaines parties varient selon différentes demande / réponse.

Maintenant, je suis la conception d'un interprète pour les données reçues. Il suffit de lire les données par des positions est OK, mais ne semble pas cool quand j'ai une douzaine de différents formats de réponse. Je pense actuellement à créer quelques struct à cette fin, mais je ne sais pas comment il aller avec un rembourrage.

Peut-être qu'il ya une meilleure façon?


Related:

Était-ce utile?

La solution

Je l'ai fait d'innombrables fois avant: il est un scénario très commun. Il y a un certain nombre de choses que je fais presque toujours.

Ne vous inquiétez pas trop sur ce qui en fait la chose la plus efficace disponible.

Si nous finissons par dépenser beaucoup de temps et le déballage des paquets d'emballage, nous pouvons toujours changer pour être plus efficace. Alors que je ne l'ai pas rencontré un cas où je devais encore, je n'ai pas été mise en œuvre des routeurs de réseau!

Alors que l'aide / structs syndicats est l'approche la plus efficace en terme d'exécution, il est livré avec un certain nombre de complications: convaincre votre compilateur pour emballer les structs / syndicats pour correspondre à la structure d'octets des paquets dont vous avez besoin, le travail pour éviter l'alignement et les questions de endianness, et un manque de sécurité car il n'y a pas ou peu d'occasions de faire des vérifications de santé d'esprit sur debug.

je le vent souvent avec une architecture, y compris le genre de choses suivantes:

  • Une classe de base de paquets. Tous les champs de données communes sont accessibles (mais non modifiable). Si les données ne sont pas stockées dans un format compressé, puis il y a une fonction virtuelle qui produira un paquet emballé.
  • Un certain nombre de classes de présentation pour les types de paquets spécifiques, dérivés du type de paquet commun. Si nous utilisons une fonction d'emballage, chaque classe de présentation doit la mettre en œuvre.
  • Tout ce qui peut être déduite du type de la classe de présentation (par exemple un identifiant de type de paquet à partir d'un champ de données commun), est traitée dans le cadre de l'initialisation et est autrement non modifiable.
  • Chaque classe de présentation peut être construite à partir d'un paquet non emballé, ou échoueront élégamment si les données de paquets est invalide pour le ce type. Cela peut ensuite être enveloppé dans une usine pour plus de commodité.
  • Si nous n'avons RTTI disponibles, nous pouvons obtenir « RTTI pauvre homme » en utilisant l'identifiant de paquet pour déterminer quelle classe de présentation spécifique d'un objet est vraiment.

Dans tout cela, il est possible (même si seulement pour debug) pour vérifier que chaque champ qui est modifiable est réglé sur une valeur saine d'esprit. Alors qu'il pourrait sembler beaucoup de travail, il est très difficile d'avoir un paquet formaté validement, un paquets pré-emballés contenu peut être easilly vérifié à l'oeil à l'aide d'un débogueur (car il est dans les variables normales de format plate-forme native).

Si nous devons mettre en œuvre un système de stockage plus efficace, que trop peut être enveloppé dans cette abstraction avec peu de frais de performances supplémentaires.

Autres conseils

Vous devez utiliser struct et ou les syndicats. Vous devez vous assurer que vos données sont correctement emballé des deux côtés de la connexion et vous voudrez peut-être se traduire par et de l'ordre des octets du réseau à chaque extrémité s'il y a une chance que de chaque côté de la connexion pourrait être en cours d'exécution avec un autre endianess.

Par exemple:

#pragma pack(push)  /* push current alignment to stack */
#pragma pack(1)     /* set alignment to 1 byte boundary */
typedef struct {
    unsigned int    packetID;  // identifies packet in one direction
    unsigned int    data_length;
    char            receipt_flag;  // indicates to ack packet or keep sending packet till acked
    char            data[]; // this is typically ascii string data w/ \n terminated fields but could also be binary
} tPacketBuffer ;
#pragma pack(pop)   /* restore original alignment from stack */

et ensuite lors de l'affectation:

packetBuffer.packetID = htonl(123456);

et puis lors de la réception:

packetBuffer.packetID = ntohl(packetBuffer.packetID);

Voici quelques discussions de Endianness et Alignement et structure d'emballage

Si vous n'emballez pas la structure, il va finir par aligné sur les limites des mots et la mise en page interne de la structure et sa taille sera incorrecte.

Il est difficile de dire quelle est la meilleure solution est sans connaître le format exact (s) des données. Avez-vous envisagé d'utiliser les syndicats?

Je suis d'accord avec Wuggy. Vous pouvez également utiliser la génération de code pour ce faire. Utilisez un simple fichier définition de données pour définir tous vos types de paquets, puis exécuter un script python dessus pour générer des structures prototypes et les fonctions de serialiation / délinéarisation pour chacun d'eux.

Ceci est une solution "out-of-the-box", mais je vous suggère de jeter un oeil à la Python

scroll top