Bonjour,
J'ai un programme python qu utilise la fonction pack du module struct. Et j'aimerais avoir son équivalent en langage C.
Merci
Bonjour,
J'ai un programme python qu utilise la fonction pack du module struct. Et j'aimerais avoir son équivalent en langage C.
Merci
Que fait cette fonction ? Quel est le contexte ? Peux-tu décrire le cas d'application ?
Bonjour,
Merci pour ta réponse.
Je ne connais pas trop python, mais elle à l'air d'être utilisé pour "formater" des chaines de caractères.
Par exemple :où l est un entier.
Code : Sélectionner tout - Visualiser dans une fenêtre à part x += pack("B",l & 0x7F)
A chaque fois qu'elle est utilisé, c'est pour des chaines de caractères.
Si j'en crois la documentation (2.7 ou 3.6), struct permet la conversion string <-> octets.
Ca ressemble terriblement à sprintf(output_buffer, "format", v1, v2, ...).struct.pack(fmt, v1, v2, ...) Return a string containing the values v1, v2, ... packed according to the given format. The arguments must match the values required by the format exactly
Ok, cette fonction produit une séquence d'octets qui peut être affectée à un enregistrement C défini avec l'arrangement correspondant. Il n'y a pas lieu d'y avoir d'équivalent puisque cette fonction est justement destinée à l'interopérabilité vers C. L'équivalent c'est une struct compatible avec le format décrit.
Je pose donc à nouveau la question :
C'est pour envoyer des requêtes dans un certain protocole à un serveur
Certes mais dans quel cadre, comment ça se passe ? Que cherches-tu à faire en C qui nécessite cette opération ? Où est le programme C ? Où est le script Python ? Comment doivent-ils communiquer ?
Voilà le script python que j'aimerais traduire en C :
Et la fonction getLenOf :
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
18
19
20
21 TYPE_ENUM = 0 TYPE_STRING = 2 TYPE_BYTES = 2 protocolVersion = 0 source_id = "sender" destination_id = "receiver" server = "10.2.182.26" namespace = "urn:dial-multiscreen-org:service:dial:1" data = "{\"type\":\"GET CONNECTION\",\"origin\":{}}" lnData = getLenOf(data) socket = socket.socket() socket = ssl.wrap_socket(socket) socket.connect((server,1900)) msg = pack(">BBBB%dsBB%dsBB%dsBBB%ds%ds" % (len(source_id),len(destination_id),len(namespace),len(lnData),len(data)),getType(1,TYPE_ENUM),protocolVersion,getType(2,TYPE_STRING),len(source_id),source_id,getType(3,TYPE_STRING),len(destination_id),destination_id,getType(4,TYPE_STRING),len(namespace),namespace,getType(5,TYPE_ENUM),0,getType(6,TYPE_BYTES),lnData,data) msg = pack(">I%ds" % (len(msg)),len(msg),msg) socket.write(msg)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 def getLenOf(s): x = "" l = len(s) while(l > 0x7F): x += pack("B",l & 0x7F | 0x80) l >>= 7 x += pack("B",l & 0x7F) return x
Il te suffit de mettre tous ces champs dans un enregistrement (struct) et de :
- l'envoyer tel quel si les chaînes sont stockées dans des buffers de taille fixe ;
- écrire une fonction qui le sérialise vers un flux si les chaînes sont de longueur variable.
Mais struct c'est juste un ensemble de variable, non ?
Oui.. et ? C'est justement ce que fait pack : concaténer une séquence de données telle qu'elle serait arrangée en C.
faut juste faire attention au padding, et en général pour ce genre de truc on l'inhibe pour avoir la main sur le formatage des données (pragma ou attributes en gcc/clang).
Je ne suis pas sur d'avoir compris
Le but est de remplir un buffer d'octets dans un format donné. On peut définir une fonction pour les 3 types de pack (B,%ds et I) et les utiliser pour remplir le buffer
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
18
19
20
21
22
23
24
25
26
27
28 unsigned pack_B( uint8_t* buf , unsigned offset , uint8_t v ) { buf[offset] = v; return offset+1; } unsigned pack_pct_ds( uint8_t* buf , unsigned offset, char const *v ) { size_t lg = strlen( v ); memcpy( buf + offset , v , lg ); return offset + lg; } unsigned pack_I( uint8_t* buf , unsigned offset , uint32_t v ) { buf[offset] = v >> 24; buf[offset + 1] = 0xff & (v >> 16); buf[offset + 2] = 0xff & (v >> 8); buf[offset + 3] = 0xff & v; return offset + 4; } void do_it() { uint8_t buffer[4096]; unsigned offset = 4; // reserver 4 octets pour le pack("I") fait en dernier offset = pack_B( buffer , offset , getType(1, TYPE_ENUM) ); offset = pack_B( buffer , offset , protocolVersion ); offset = pack_B( buffer , offset , getType(2, TYPE_STRING) ); offset = pack_B( buffer , offset , strlen(source_id) ); offset = pack_pct_ds( buffer , offset , source_id ); ... ... offset += pack_I( buffer , 0 , offset ); send( socket, buffer , offset, 0); }
Du coup, j'ai ça :
Bon, ben quand j'envoie au serveur, je ne reçoit rien.
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
18
19
20
21
22
23
24
25
26 uint8_t buffer[4096]; unsigned offset = 4; // reserver 4 octets pour le pack("I") fait en dernier offset = pack_B( buffer , offset , strlen(source_id) ); offset = pack_B( buffer , offset , strlen(destination_id) ); offset = pack_B( buffer , offset , strlen(namespace) ); offset = pack_B( buffer , offset , 1 ); offset = pack_B( buffer , offset , strlen(data) ); offset = pack_B( buffer , offset , getType(1, TYPE_ENUM) ); offset = pack_B( buffer , offset , protocolVersion ); offset = pack_B( buffer , offset , getType(2, TYPE_STRING) ); offset = pack_B( buffer , offset , strlen(source_id) ); offset = pack_pct_ds( buffer , offset , source_id ); offset = pack_B( buffer , offset , getType(3, TYPE_STRING) ); offset = pack_B( buffer , offset , strlen(destination_id) ); offset = pack_pct_ds( buffer , offset , destination_id ); offset = pack_B( buffer , offset , getType(4, TYPE_STRING) ); offset = pack_B( buffer , offset , strlen(namespace) ); offset = pack_pct_ds( buffer , offset , namespace ); offset = pack_B( buffer , offset , getType(5, TYPE_ENUM) ); offset = pack_B( buffer , offset , payloadType ); offset = pack_B( buffer , offset , getType(6, TYPE_ENUM) ); offset = pack_B( buffer , offset , getLenOf(data) ); offset = pack_pct_ds( buffer , offset , namespace ); offset += pack_I( buffer , 0 , offset ); send(sock, buffer , offset, 0);
Le script python avat aussi une socket sécurisé avec socket_wrap.
Est-ce qu'il est nécessaire en C que ma socket soit sécurisé ?
Ta séquence de pack n'est pas bonne, les données passées en % n'ont pas être traitées (elle fournissent la longueurs des %ds dans le format mais ne sont pas dans le buffer). Il doit y avoir exactement le même nombre d'appels que de "B" "%ds" et "I" que dans le format, j'ai indiqué les 5 premiers. Et attention au lnData qui doit être calculé et transmis sous la forme d'une chaîne.
Si le socket était sécurisé, il y a de forte chance que tu nécessites de faire de même.
Mais à quoi correspond %ds ?
Les B c'est pour unsigned char, I pour unsigned int...
Mais là on les copie dans le buffer les %ds, non ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part memcpy( buf + offset , v , lg );
Si tu dois envoyer dans cet ordre un byte, un short (16bit), deux bytes, un int (32bits) alors tu fais une structure :
Tu la remplis, tu l'écris avec un write (attention à l'endianness) et basta.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 struct foo { unsigned char first_byte ; short first_short; unsigned char second_byte; unsigned char third_byte; int last_int; } __attribute__ (( packed ));
J'ai présenté la syntaxe d'attribut valide avec gcc/clang, mais on peut aussi un pragma.
Je suis pas obligé d'utiliser send pour envoyer un flux de données sur le réseau ?
Donc c'est un peu comme pour écrire dans un fichier en mode binaire, sauf qu'on utilise write au lieu de fwrite, comme le montre cet exemple ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 typedef struct { int age; char nom[30]; char prenom[30]; char adresse[60]; int nombreFreres; }SPersonne ; SPersonne personne; //Je déclare une variable de type SPersonne fwrite( &personne , sizeof(personne) , 1 , fichier);
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager