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

Hé les gars, question d’un débutant C / Networking …

Je suis en train de programmer des sockets en C et d’essayer de résoudre les problèmes d’ordre des octets. Ma demande (envoi) va bien, mais lorsque je reçois des données, mes octets sont tous hors service. Je commence par quelque chose comme ça …

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

En traitant cette réponse, chaque mot de 16 bits semble avoir ses octets inversés (j’utilise UDP). J’ai essayé de résoudre ce problème en faisant quelque chose comme ça …

  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 bien lorsque je traite les données comme un court-métrage. Toutefois, si je redéfinis le pointeur sur un caractère, les octets sont inversés. Qu’est-ce que je fais mal?

Merci!

Ok, il semble y avoir des problèmes avec ce que vous faites à deux niveaux différents. Une partie de la confusion semble résulter de votre utilisation des pointeurs, du type d’objects qu’ils pointent, puis de l’interprétation du codage des valeurs dans la mémoire pointée par le ou les pointeurs.

Le codage des entités multi-octets en mémoire correspond à ce que l’on appelle l’endianess. Les deux codages courants sont appelés Little Endian (LE) et Big Endian (BE). Avec LE, une quantité de 16 bits, telle qu’un court-circuit, est d’abord codée en octet de poids faible (LSB). Sous BE, l’octet de poids fort (MSB) est codé en premier.

Par convention, les protocoles réseau codent normalement les éléments dans ce que nous appelons “ordre d’octet réseau” (NBO), qui se trouve être identique à BE. Si vous envoyez et recevez des mémoires tampons sur des plates-formes big endian, vous ne rencontrerez aucun problème de conversion. Cependant, votre code serait alors dépendant de la convention BE pour la plate-forme. Si vous voulez écrire du code portable qui fonctionne correctement sur les plates-formes LE et BE, vous ne devez pas supposer que la plate-forme est endianess.

Atteindre la portabilité endian est l’object de routines telles que ntohs () , ntohl () , htons () et 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 () – Convertit une valeur courte de la commande de l’hôte en commande du réseau (pour l’envoi)
  • htonl () – Convertit une valeur longue de l’ordre de l’hôte en ordre du réseau (pour l’envoi)
  • ntohs () – Convertit une valeur courte de la commande réseau en commande hôte (après réception)
  • ntohl () – Convertit une valeur longue d’une commande réseau en une commande hôte (après réception)

Sachez que votre commentaire sur l’access à la mémoire lors de la conversion en caractères n’a pas d’incidence sur l’ordre réel des entités en mémoire. En d’autres termes, si vous accédez au tampon sous forme d’une série d’octets, vous verrez les octets dans l’ordre dans lequel ils ont été réellement encodés en mémoire, que vous disposiez d’une machine BE ou LE. Donc, si vous regardez un tampon encodé NBO après la réception, le MSB sera toujours le premier. Si vous examinez le tampon de sortie après avoir reconverti la commande en ordre d’hôte, si vous avez BE machine, l’ordre des octets ne sera pas modifié. Inversement, sur une machine LE, les octets seront tous inversés dans la mémoire tampon convertie.

Enfin, dans votre boucle de conversion, la variable total fait référence à des octets. Cependant, vous accédez au tampon en tant que shorts . Votre bouclier ne devrait pas être total , mais devrait être:

total / sizeof( unsigned short )

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

Cela fonctionne bien lorsque je traite les données comme un court-métrage. Toutefois, si je redéfinis le pointeur sur un caractère, les octets sont inversés.

C’est ce à quoi je m’attendrais.

Qu’est-ce que je fais mal?

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), des courts-métrages ou des longs (ce qui est le cas).

Google pour les tutoriels associés aux ntohs , htons et htons .

On ne sait pas ce aResponse représente une aResponse (chaîne de caractères? Struct?). La finalité ne concerne que les valeurs numériques et non les caractères. Vous devez également vous assurer que, du côté de l’expéditeur, toutes les valeurs numériques sont converties de l’hôte en ordre d’octet réseau ( hton* ).

Outre votre question initiale (à laquelle, je pense, la réponse a déjà été donnée), vous devriez jeter un coup d’œil à votre déclaration de malloc . malloc alloue des octets et un short non signé est plus susceptible d’être deux octets.

Votre déclaration devrait ressembler à:

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

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 ne s’agit que d’un tableau, il ne faut pas en faire une histoire, comment l’expéditeur envoie-t-il ses données?

Pour un seul octet, nous pourrions ne pas nous soucier de l’ordre des octets.