web-dev-qa-db-fra.com

Comprendre htonl () et ntohl ()

J'essaie d'utiliser des sockets unix pour tester l'envoi de paquets udp à localhost.

Je crois comprendre que lors de la configuration de l'adresse IP et du port afin d'envoyer des paquets, je remplissais mon sockaddr_in avec les valeurs converties en ordre d'octets réseau . Je suis sur OSX et je suis étonné de ce

printf("ntohl: %d\n", ntohl(4711));
printf("htonl: %d\n", htonl(4711));
printf("plain: %d\n", 4711);

Impressions

ntohl: 1729232896
htonl: 1729232896
plain: 4711

Donc, ni l'une ni l'autre des fonctions ne renvoie réellement la valeur simple. Je me serais attendu à ce que les résultats diffèrent, car x86 est un petit bout (afaik), ou identiques et identiques au nombre 4711. De toute évidence, je ne comprends pas ce que htonl et ntohl et leurs variantes font. Qu'est-ce que je rate?

Le code pertinent est le suivant:

int main(int argc, char *argv[])
{
   if (argc != 4)
   {
      fprintf(stderr, "%s\n", HELP);
      exit(-1);
   }

   in_addr_t rec_addr = inet_addr(argv[1]); // first arg is '127.0.0.1'
   in_port_t rec_port = atoi(argv[2]);      // second arg is port number
   printf("Address is %s\nPort is %d\n", argv[1], rec_port);
   char* inpath = argv[3];

   char* file_buf;
   unsigned long file_size = readFile(inpath, &file_buf); // I am trying to send a file
   if (file_size > 0)
   {
      struct sockaddr_in dest;
      dest.sin_family      = AF_INET;
      dest.sin_addr.s_addr = rec_addr; // here I would use htons
      dest.sin_port        = rec_port;
      printf("ntohs: %d\n", ntohl(4711));
      printf("htons: %d\n", htonl(4711));
      printf("plain: %d\n", 4711);
      int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
      if (socket_fd != -1)
      {
         int error;
         error = sendto(socket_fd, file_buf, file_size + 1, 0, (struct sockaddr*)&dest, sizeof(dest));
         if (error == -1)
            fprintf(stderr, "%s\n", strerror(errno));
         else printf("Sent %d bytes.\n", error);
      }
   }

   free(file_buf);
   return 0;
}
8
oarfish

Les deux fonctions inversent l'ordre des octets. Pourquoi cela renverrait l'argument lui-même?

Essayez htons(ntohs(4711)) et ntohs(htons(4711)).

5
Michel de Ruiter

Comme d'autres l'ont mentionné, htons et ntohs inversent l'ordre des octets sur une machine little-endian et ne fonctionnent pas sur les machines big-endian.

Ce qui n'a pas été mentionné, c'est que ces fonctions prennent une valeur de 16 bits et retournent une valeur de 16 bits. Si vous souhaitez convertir des valeurs 32 bits, vous souhaitez plutôt utiliser htonl et ntohl.

Les noms de ces fonctions proviennent des tailles traditionnelles de certains types de données. s représente short tandis que l correspond à long. short est généralement 16 bits alors que sur les systèmes plus anciens long était 32 bits. 

Dans votre code, vous n'avez pas besoin d'appeler htonl sur rec_addr, car cette valeur a été renvoyée par inet_addr et cette fonction renvoie l'adresse dans l'ordre des octets du réseau.

Vous devez toutefois appeler htons sur rec_port.

7
dbush

"Ordre des octets du réseau" signifie toujours big endian.

"L'ordre des octets de l'hôte" dépend de l'architecture de l'hôte. Selon le processeur, l’ordre des octets de l’hôte peut être petit, grand ou autre. (g) la libc s'adapte à l'architecture de l'hôte.

L’architecture d’Intel étant peu évolutive, cela signifie que les deux fonctions agissent de la même manière: inverser l’ordre des octets.

4
gudok

ces fonctions sont mal nommées. Host to network et network to Host sont en réalité la même chose et devraient être appelés 'changer d'endianisme s'il s'agit d'une petite machine endian'

Donc, sur une petite machine endian vous faites

net, ie be, number = htonl / ntohl (le number)

et envoyez le numéro sur le fil. Et quand vous obtenez un grand nombre final du fil

le num = htonl/ntohl (net ,ie be, number)

sur une grosse machine 

net, ie be, number = htonl / ntohl (be number)

et

 be num = htonl/ntohl (net ,ie be, number)

et dans les derniers cas, vous voyez que ces fonctions ne font rien

2
pm100