9 votes

Ordre des octets avec un grand tableau de caractères en C

Je fais de la programmation de socket en C, et j'essaie de résoudre des problèmes d'ordre d'octet. Ma requête (envoi) est correcte, mais lorsque je reçois des données, mes octets sont tous dans le désordre. Je commence par quelque chose comme ça :

char * aResponse= (char *)malloc(512);
int total = recv(sock, aResponse, 511, 0);

Lorsque je traite cette réponse, chaque mot de 16 bits semble avoir ses octets inversés (j'utilise UDP). J'ai essayé de corriger cela en faisant quelque chose comme ceci :

    unsigned short * _netOrder= (unsigned short *)aResponse;
    unsigned short * newhostOrder= (unsigned short *)malloc(total);
    for (i = 0; i < total; ++i)
    {
         newhostOrder[i] = ntohs(_netOrder[i]);
    }

Cela fonctionne correctement lorsque je traite les données comme un short, mais si je transforme le pointeur en char, les octets sont inversés. Qu'est-ce qui ne va pas ?

12voto

Tall Jeff Points 6065

Ok, il semble qu'il y ait des problèmes avec ce que vous faites à deux niveaux différents. Une partie de la confusion semble provenir de votre utilisation de pointeurs, du type d'objets vers lesquels ils pointent, et de l'interprétation du codage des valeurs dans la mémoire pointée par le(s) pointeur(s).

Le codage d'entités de plusieurs octets dans la mémoire est ce que l'on appelle l'endianité. Les deux codages les plus courants sont les suivants Petit Endien (LE) et Grand Endien (BE). Avec LE, une quantité de 16 bits telle qu'un numéro court est codée en premier par l'octet le moins significatif (LSB). Avec BE, l'octet le plus significatif (MSB) est codé en premier.

Par convention, les protocoles de réseau codent normalement les choses dans ce que nous appelons le "network byte order" (NBO), qui se trouve être le même que BE. Si vous envoyez et recevez des tampons de mémoire sur des plates-formes big endian, vous ne rencontrerez pas de problèmes de conversion. Cependant, votre code dépendrait alors de la plate-forme et de la convention BE. Si vous voulez écrire un code portable qui fonctionne correctement sur les plates-formes LE et BE, vous ne devez pas présumer de l'endianité de la plate-forme.

La portabilité de l'endian est l'objectif de routines telles que ntohs() , ntohl() , htons() y htonl() . Ces fonctions/macros sont définies sur une plate-forme donnée pour effectuer les conversions nécessaires aux extrémités d'envoi et de réception :

  • htons() - Convertir la valeur courte de l'ordre hôte en ordre réseau (pour l'envoi)
  • htonl() - Conversion d'une valeur longue de l'ordre de l'hôte à l'ordre du réseau (pour l'envoi)
  • ntohs() - Conversion de la valeur courte de l'ordre réseau en ordre hôte (après réception)
  • ntohl() - Conversion de la valeur longue de l'ordre réseau en ordre hôte (après réception)

Comprenez que votre commentaire sur l'accès à la mémoire lors de la réintégration des personnages n'a aucune incidence sur l'ordre réel des entités dans la mémoire. En d'autres termes, si vous accédez à la mémoire tampon en tant que série d'octets, vous verrez les octets dans l'ordre dans lequel ils ont été encodés dans la mémoire, que vous ayez une machine BE ou LE. Ainsi, si vous regardez une mémoire tampon codée NBO après réception, le MSB sera toujours en premier. Si vous regardez le tampon de sortie après l'avoir reconverti en ordre hôte, si vous avez une machine BE, l'ordre des octets sera inchangé. Inversement, sur une machine LE, les octets seront tous inversés dans le tampon converti.

Enfin, dans votre boucle de conversion, la variable total se réfère à des octets. Cependant, vous accédez à la mémoire tampon en tant que shorts . La protection de la boucle ne doit pas être total mais devrait l'être :

total / sizeof( unsigned short )

pour tenir compte de la nature à double octet de chaque short .

3voto

ChrisW Points 37322

Cela fonctionne correctement lorsque je traite les données comme un short, mais si je transforme le pointeur en char, les octets sont inversés.

C'est ce à quoi je m'attendais.

Qu'est-ce que je fais de travers ?

Vous devez savoir ce que l'expéditeur a envoyé : savoir si les données sont des octets (qui n'ont pas besoin d'être inversés), ou des courts ou des longs (qui en ont besoin).

Google pour les tutoriels associés à la ntohs , htons y htons API.

2voto

Zach Scrivena Points 15052

Il n'est pas clair ce que aResponse représente (chaîne de caractères ? structure ?). Endiannée n'est pertinent que pour les valeurs numériques, pas pour les char s. Vous devez également vous assurer que, du côté de l'expéditeur, toutes les valeurs numériques sont converties de l'ordre des octets de l'hôte à l'ordre des octets du réseau ( hton* ).

1voto

olli Points 1945

Outre votre question initiale (à laquelle je pense qu'il a déjà été répondu), vous devriez jeter un coup d'œil à vos malloc déclaration. malloc alloue des octets et un short non signé a de fortes chances d'être composé de deux octets.

Votre déclaration devrait ressembler à ceci :

unsigned short *ptr = (unsigned short*) malloc(total * sizeof(unsigned short));

0voto

CiNN Points 3893

L'ordre des octets du réseau est big endian, vous devez donc le convertir en little endian si vous voulez que cela ait un sens, mais s'il s'agit seulement d'un tableau, cela ne devrait pas poser de problème, comment l'expéditeur envoie-t-il ses données ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X