IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Des int dans un buffer binaire


Sujet :

C++

  1. #1
    Membre habitué Avatar de Colbix
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    266
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 266
    Points : 150
    Points
    150
    Par défaut Des int dans un buffer binaire
    Bonjour à tous,

    Je dois envoyer envoyer dans un packet tcp/ip des données sous un certain format. Le problème ne vient pas de tcp/ip, mais plus de la manière dont je doit remplire le packet.

    En gros le contenu du packet doit comporter 5 int32 puis 2 int16 (tous ça en format binaire).

    Je voulais savoir : d'après vous comment je peut faire ça joliment ?
    - Gérer un buffer en C et faire des shift de mes int ?
    - ... ?

    Merci d'avance
    Problème résolu ? N'oubliez pas le bouton ainsi que le "Pertinent". Ça fait du bien au forum.

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    Est ce que tu as le droit de les envoyer sous forme de texte séparé par un caractère spécial ("," par exemple) car ainsi, tu t'affranchis des différences d'architecture poid fort/poid faible (et puis, c'e'st plus facile à débugger)
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  3. #3
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Souvent tu trouves des fonctions de type hton[s/l] (host->network) et l'inverse ntoh[s/l] (network->host). Sinon, je te conseille de le faire.

  4. #4
    Membre habitué Avatar de Colbix
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    266
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 266
    Points : 150
    Points
    150
    Par défaut
    Citation Envoyé par ram-0000 Voir le message
    Est ce que tu as le droit de les envoyer sous forme de texte séparé par un caractère spécial ("," par exemple) car ainsi, tu t'affranchis des différences d'architecture poid fort/poid faible (et puis, c'e'st plus facile à débugger)
    Malheureusement, je dois me plier à l'architecture déjà établie... Je ne peux donc pas changer quoi que ce soit et je dois respecter la norme établie...

    J'aimerai faire un truc du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    			void* buffer = malloc(size);
    			if(buffer == NULL)
    				return false;
    			// Init Header of packet
    			buffer[0] = var1;
    			buffer[4] = var2;
    			buffer[8] = var3;
    			buffer[12] = var4;
    			buffer[16] = var5;
    			// Init body
    			buffer[20] = var6;
    			buffer[22] = var7;
    Là, le compilateur posera pbl évidemment.

    Salut,
    Souvent tu trouves des fonctions de type hton[s/l] (host->network) et l'inverse ntoh[s/l] (network->host). Sinon, je te conseille de le faire.
    Je vais me renseigner .



    Merci pour vos réponses rapides
    Problème résolu ? N'oubliez pas le bouton ainsi que le "Pertinent". Ça fait du bien au forum.

  5. #5
    Membre habitué Avatar de Colbix
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    266
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 266
    Points : 150
    Points
    150
    Par défaut
    J'ai essayé avec un struct, mais j'ai encore un problème...

    Pour ce qui est des int 32 et 16 c'est ok, mais je dois pouvoir rajouter du texte (des paramètre en fait). Ce texte est donc de taille variable. Pour mon struct ça pose donc un problème...

    Une idée pour résoudre ce problème ?
    Problème résolu ? N'oubliez pas le bouton ainsi que le "Pertinent". Ça fait du bien au forum.

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Construire un message composé : format de type LV (longueur/valeur) ou TLV (type longueur valeur).
    [EDIT]: pour du texte, faudra quand même choisir un encodage

  7. #7
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Si tu connais la structure de ton paquet, tu peux une structure :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct packet
    {
    type_1 var1;
    type_2 var2;
    type_3 var3;
    ...
    };
    où les types types pourrait être des flags, adresses réseaux (source et destination), ...

    Ensuite, tu envoies la struct sous la forme d'un buffer, en données brutes

  8. #8
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Les structs peuvent générer des problèmes d'alignement.

  9. #9
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    J'ai rien dit dans ce cas

  10. #10
    Membre habitué Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Points : 190
    Points
    190
    Par défaut
    Dans ce genre de cas, le mieux c'est d'écrire un serializer/deserializer.
    Evidemment, c'est un peu long mais une fois que c'est fait, tu peux le réutiliser à l'infini.

    Un truc dans ce genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class Serializer
        {
        public:
            bool init ( void * outputbuffer , int outputsize ) ;
            bool add ( uint16 c ) ;
            bool add ( uint32 c ) ;
            bool add ( const char * string ) ;
        };
     
    class Deserializer
        {
        public:
            bool init ( const void * inputbuffer , int inputsize ) ;
            bool get ( uint16 * c ) ;
            bool get ( uint32 * c ) ;
            bool get ( char  * string , int maxlength ) ;
        };
    du coup, pour fabriquer ton paquet, ça donne ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        my_serializer.add( var1 ) ; // var1 est un uint32 -> ok
        my_serializer.add( var2 ) ; // var2 est un uint32 -> ok
        my_serializer.add( var3 ) ; // var3 est un uint32 -> ok
        my_serializer.add( var4 ) ; // var4 est un uint32 -> ok
        my_serializer.add( var5 ) ; // var5 est un uint32 -> ok
        my_serializer.add( var6 ) ; // var6 est un uint16 -> ok
        my_serializer.add( var7 ) ; // var7 est un uint16 -> ok
        my_serializer.add("ho ! les beaux paramètres que voila") ; // char * -> ok
    Tous les pb d'endianness sont gérés dedans (à toi de choisir comment).
    Pour le add( const char * ), tu peux décider d'écrire d'abord la longueur sur un uint16 puis les chars à la suite ou de copier les chars et d'ajouter un 0 à la fin...

    L'important étant que le serializer et le deserializer soient d'accord aux 2 bouts de la liaison.

    En tous cas, ça te permettera d'avoir un code à ne tester qu'une fois et bien isolé du reste. Et si les spec du format d'échange de données change, tu n'auras qu'un code à modifier.
    C'est la base de la programmation modulaire.

    Hadrien
    [WinXP sp3 / Visual 2005 / Eclipse Ganymede / Python 2.6]
    Hadrien

  11. #11
    Membre habitué Avatar de Colbix
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    266
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 266
    Points : 150
    Points
    150
    Par défaut
    C'est une bonne idée.

    J'ai commencé a faire un truc semblable, mais en utilisant des struct donc je modifie la taille de manière dynamique. C'est très bourrin, j'avoue...

    Je vais encore un peu y réfléchir...

    Il y a le pbl big-endian -> little-endian aussi :s

    Merci pour votre aide


    [Edit] si je veux faire un Serializer. Ton int16 et int32, comment les déclarer ?
    Problème résolu ? N'oubliez pas le bouton ainsi que le "Pertinent". Ça fait du bien au forum.

  12. #12
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Juste quelques remarques sur la solution proposée, histoire de partir du bon pied :
    -> Problème de const,
    -> Les paramètres peuvent être passées par référence (les pointeurs ne servent à rien sinon introduire du risque)
    -> Utiliser std::string au lieu de pointeur sur char

    Pour les conversions, des macros existent plus ou moins sous la même forme depuis des lustres avec les décalages kifo.

    uintXX_t si ton compilo implémente stdint.h. ; sinon Boost.Integer.

  13. #13
    Membre habitué Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Points : 190
    Points
    190
    Par défaut
    C'est ultra simple :
    J'utilise la surchage des méthodes.
    Pour tous les types que tu veux pouvoir serialiser, tu ajoute un nouveau add dans le Serializer, et un nouveau get dans le Deserializer.
    Bien sûr, il vaut mieux que ces types ne soient pas trop évolués pour que l'outil reste générique.

    J'avais utilisé int16 et int32 pour fixer les idées mais c'est ce que tu veux.
    Pour faire encore plus générique, le mieux, c'est d'utiliser les types natifs du langage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Serializer
        {
        public:
            bool add ( char a ) ;
            bool add ( unsigned char a ) ;
            bool add ( short b ) ;
            bool add ( unsigned short b ) ;
            bool add ( int b ) ;
            bool add ( unsigned int b ) ;
            bool add ( long b ) ;
            bool add ( unsigned long b ) ;
        };
    Avec ça, tu gères tous les types entiers.
    Ensuite, dans l'implementation, on peut imaginer une fonction de privée de base qui gère juste les octets.
    En fonction de l'endianess, tu vas sériliaser les autres types en parcourant leurs octets dans un sens ou dans l'autre.

    Attention, il y 2 endianess à gérer, celle des données qui vont circuler (sur le réseau ou sur un disque) et celle de la machine sur laquelle ton code va s'executer.

    Hadrien
    [WinXP sp3 / Visual 2005 / Eclipse Ganymede / Python 2.6]
    Hadrien

  14. #14
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Attention, rien ne te garantie que char=1 octet, short=2 ocets, int =4 octets et long = 4/8 octets.

  15. #15
    Membre habitué Avatar de sopsag
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    224
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 224
    Points : 190
    Points
    190
    Par défaut
    C'est vrai, mais je ne vois pas ce ça change, du moment qu'il existe un add/get par type dont on a besoin.
    Après, il faut jouer avec sizeof pour ne pas se faire surprendre.

    Mais juste comme ça, si un char ne fait plus un octet, comment manipuler des données à l'octet près (comme quand on retourne les 4 octets d'un long pour le convertir en big endian) ?

    Est-ce que uint8_t deviendrait un type natif ?

    Hadrien
    [WinXP sp3 / Visual 2005 / Eclipse Ganymede / Python 2.6]
    Hadrien

  16. #16
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par sopsag Voir le message
    C'est vrai, mais je ne vois pas ce ça change, du moment qu'il existe un add/get par type dont on a besoin.
    Après, il faut jouer avec sizeof pour ne pas se faire surprendre.
    C'est dans la façon d'écrire get/add (d'ailleurs, j'aurais préféré operator<< et operator>>, ce qui est cohérent avec le sens d'ajouter des données au buffer ou d'en lire)
    Citation Envoyé par sopsag Voir le message
    Mais juste comme ça, si un char ne fait plus un octet, comment manipuler des données à l'octet près (comme quand on retourne les 4 octets d'un long pour le convertir en big endian) ?
    En fait j'ai répondu un peu trop vite. La vrai relation est :
    sizeof(char)=1
    sizeof(char)<=sizeof(short)<=sizeof(int)<=sizeof(long)
    et CHAR_BITS >= 8
    sizeof(short)*CHAR_BITS >= 16, sizeof(long)*CHAR_BITS >= 32.
    Donc, en fait, un char n'est pas forcément 8 bits. Et les autres en dérivent.
    Tu peux avoir des architectures où int=short, ou int=long, voir même short=int=long. Avec le 64 bit, tu te retrouve à avoir des fois int=long et d'autre int=long long.
    Rien de très certain...
    Pour quelque chose d'un peu réutilisable : boost.Integer (voir Boost.Serialize) ou générique à base de template sur les tailles.

    Enfin, il y a des plate-forme où tu ne peux manipuler la mémoire à l'octet près car tu ne peux déréférencer que des adresses alignées (sur 32 bits par expl).
    Citation Envoyé par sopsag Voir le message
    Est-ce que uint8_t deviendrait un type natif ?
    D'après ce que j'ai compris, ça doit être dans la norme C99, mais Visual ne l'implémente pas...

  17. #17
    Membre habitué Avatar de Colbix
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    266
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 266
    Points : 150
    Points
    150
    Par défaut
    Merci pour vos réponses !

    Ca marche et c'est joli .

    A++
    Problème résolu ? N'oubliez pas le bouton ainsi que le "Pertinent". Ça fait du bien au forum.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Lire des octets dans un fichier binaire
    Par DiverSIG dans le forum Entrée/Sortie
    Réponses: 12
    Dernier message: 19/01/2009, 10h22
  2. encoder des valeurs int dans xml en binaire et sortir en txt
    Par ahelaine dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 05/09/2008, 14h40
  3. lecture dans un buffer binaire
    Par rikau2 dans le forum C++
    Réponses: 7
    Dernier message: 21/08/2007, 14h29
  4. Réponses: 19
    Dernier message: 04/06/2007, 17h12
  5. comment mettre des int dans une char??
    Par gronaze dans le forum C
    Réponses: 5
    Dernier message: 21/04/2006, 17h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo