8
votes

Création et utilisation d'une structure de plate-forme croisée en C ++

J'écris un jeu de plate-forme cross avec des capacités de réseautage (utilisant SFML et raknet ) et je suis venu à Le point où j'ai compilé le serveur sur mon serveur Ubuntu et que j'ai reçu un client sur mon Mac. Tout le développement est effectué sur mon Mac afin que j'ai initialement testé le serveur à ce sujet, et cela a fonctionné bien.

J'envoie struct code> S sur le réseau, puis simplement les jeter de Char * Code> à (par exemple) Inet :: PlayerAdded Code>. Maintenant, cela fonctionne bien (pour la plupart), mais ma question est la suivante: cela fonctionnera-t-il toujours? Cela semble une approche très fragile. La structure sera-t-elle toujours la même pareille même sur d'autres plates-formes, Windows, par exemple? Que recommanderiez-vous? P>

#pragma pack(push, 1)
struct Player
{
    int dir[2];
    int left;
    float depth;
    float elevation;
    float velocity[2];
    char character[50];
    char username[50];
};

// I have been added to the game and my ID is back
struct PlayerAdded: Packet
{
    id_type id;
    Player player;
};
#pragma pack(pop)


3 commentaires

À la bownvoter en série, une raison particulière? (La Downvote de Steve semble particulièrement flagrante)


Les points n'ont pas de sens dans un endroit comme celui-ci. Je ne m'inquiéterais pas pour ça.


Je me fiche des points, je veux savoir pourquoi chaque réponse (sauf un, le moins utile de tous) a eu un bowvote. Surtout quand l'une des réponses (bownvotes) était clairement meilleure.


3 Réponses :


9
votes

Cela ne fonctionnera pas si (entre autres) Vous essayez de le faire à partir de la machine à big-endian à la machine Big-Endian, car la représentation correcte int est inversée entre les deux.

Ceci pourrait également échouer si l'alignement ou l'emballage de votre structure passe de la machine à la machine. Et si vous avez des machines de 64 bits et certaines qui sont 32 bits?

Vous devez utiliser une bibliothèque de sérialisation portable appropriée comme Boost.Sériorialisation ou Tampons de protocole Google Pour vous assurer de disposer d'un protocole de fil (aka format de données transmissible) pouvant être décodé avec succès indépendamment du matériel.

Une fois que la bonne chose à propos de la mémoire tampon de protocole est que vous pouvez compresser les données de manière transparente à l'aide d'un flux compatible ZLIB également compatible avec les flux protobuf. J'ai effectivement fait cela, ça fonctionne bien. J'imagine que d'autres flux de décorateur peuvent être utilisés de manière analogue d'améliorer ou d'optimiser votre protocole de fil de base selon les besoins.


0 commentaires

2
votes

La réponse à "... a aménagé la même chose même sur d'autres plates-formes ..." est généralement non. C'est ainsi que même si des problèmes différents que différents processeurs et / ou une endansion différente sont adressés.

différents systèmes d'exploitation (même sur la même plate-forme matérielle) pourraient utiliser différentes représentations de données; Ceci est normalement appelé "plate-forme abi" et il est différent entre par ex. Windows 32bit / 64 bits, 32bit / 64bit Linux, MacOSX.

'# Pragma Pack' n'est que la moitié de la voie, car au-delà des restrictions d'alignement, il peut y avoir des différences de taille de type de données. Par exemple, "long" sur Windows 64 bits est de 32 bits alors qu'il est 64 bits sur Linux et MacOSX.

Cela dit, le problème n'est évidemment pas nouveau et a déjà été abordé dans le passé - la norme d'appel de la procédure à distance (RPC) contient des mécanismes permettant de définir les structures de données de manière indépendante de la plate-forme et de la manière de coder / décoder "tampons" représentant ces structures. C'est ce qu'on appelle "XDR" (représentation de données externe). Voir rfc1832. Comme la programmation va, cette roue a été réinventée plusieurs fois; Que vous converties en XML, faites le niveau bas fonctionnant avec XDR, utilisez Google :: Protobuf, Boost ou Qt :: Variante, il y a beaucoup de choix.

sur un côté purement de la mise en œuvre: pour SimplicLty, supposons simplement que "non signé INT" partout est aligné sur une limite de 32 bits; Si vous pouvez encoder toutes vos données en tant que tableau de valeurs 32 bits, le seul problème d'externalisation que vous devez traiter est l'endansnité.


0 commentaires

5
votes

Comme beaucoup des autres réponses, je conseillerais contre l'envoi de données binaires brutes si elle peut être évitée. Quelque chose comme Boost Serial ou Google Protobuf fera un bon travail sans trop de frais généraux.

Mais vous pouvez certainement créer des structures binaires multiplateformes, cela se fait tout le temps et est un moyen très valide d'échanger des données. La superposition d'une "structure" sur ces données a un sens. Cependant, vous devez faire très attention à la mise en page, heureusement que la plupart des compilateurs vous donnent de nombreuses options pour le faire. "Pack" est une telle option et prend en charge beaucoup.

Vous devez également prendre soin des tailles de données. Simple inclure STDINT.H et utilisez les types de taille fixe comme uint32_t . Soyez prudent des valeurs de points flottants, toutes les architectures ne partageront pas la même valeur, pour un flotteur 32 bits qu'ils font probablement. Aussi pour l'endianess, la plupart des architectures utiliseront la même chose et, s'ils ne le font pas, vous pouvez simplement le basculer sur le client différent.


1 commentaires

Même si la plupart des réponses étaient vraiment géniales, je pense que c'est celui qui m'a le plus aidé. Je pense que je vais lui donner un coup de feu, et moi, si j'ai jamais frappé une barrière avec cette méthode, je saurai quoi utiliser.