web-dev-qa-db-fra.com

Fonction htons () dans la programmation de socket

Je suis nouveau dans la programmation de socket et j'essaie de comprendre le fonctionnement de htons(). J'ai lu quelques tutoriels sur Internet comme this et this un par exemple. Mais je ne pouvais pas comprendre ce que htons() fait exactement. J'ai essayé le code suivant:

#include <stdio.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

int main( int argc, char *argv[] )
{
    int sockfd, newsockfd, portno, clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int  n;

    /* First call to socket() function */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
    {
        perror("ERROR opening socket");
        exit(1);
    }
    /* Initialize socket structure */
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = 5001;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    /* Now bind the Host address using bind() call.*/
    if (bind(sockfd, (struct sockaddr *) &serv_addr,
                          sizeof(serv_addr)) < 0)
    {
         perror("ERROR on binding");
         exit(1);
    }

    /* Now start listening for the clients, here process will
    * go in sleep mode and will wait for the incoming connection
    */
    listen(sockfd,5);
    clilen = sizeof(cli_addr);

    /* Accept actual connection from the client */
    newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, 
                                &clilen);
    if (newsockfd < 0) 
    {
        perror("ERROR on accept");
        exit(1);
    }
    /* If connection is established then start communicating */
    bzero(buffer,256);
    n = read( newsockfd,buffer,255 );
    if (n < 0)
    {
        perror("ERROR reading from socket");
        exit(1);
    }
    printf("Here is the message: %s\n",buffer);

    /* Write a response to the client */
    n = write(newsockfd,"I got your message",18);
    if (n < 0)
    {
        perror("ERROR writing to socket");
        exit(1);
    }
    return 0; 
}

La valeur de sin_port était affiché comme 35091 pendant le débogage et je ne comprends pas comment portno a changé de 5001 à 35091. Quelqu'un pourrait-il expliquer la raison de ce changement de valeur s'il vous plaît?

40
User123422

Cela a à voir avec l'ordre dans lequel les octets sont stockés en mémoire. Le nombre décimal 5001 Est 0x1389 En hexadécimal. Les octets concernés sont donc 0x13 Et 0x89. De nombreux appareils stockent les numéros au format little-endian, ce qui signifie que l'octet le moins significatif vient en premier. Donc, dans cet exemple particulier, cela signifie qu’en mémoire le nombre 5001 Sera stocké comme

0x89 0x13

La fonction htons() permet de s'assurer que les numéros sont stockés en mémoire dans l'ordre des octets du réseau, avec l'octet le plus significatif en premier. Il va donc échanger les octets constituant le numéro afin que dans la mémoire les octets soient stockés dans l'ordre

0x13 0x89

Sur une machine little-endian, le nombre d'octets échangés est 0x8913 En hexadécimal, ce qui correspond à 35091 En notation décimale. Notez que si vous travailliez sur une machine big-endian, la fonction htons() n'aura besoin d'aucun échange car le numéro serait déjà stocké correctement dans la mémoire.

La raison sous-jacente de tout cet échange est liée aux protocoles réseau utilisés, qui exigent que les paquets transmis utilisent l'ordre des octets du réseau.

93
brm

htons est Host-to-network short

Cela signifie que cela fonctionne sur des entiers courts de 16 bits. c'est-à-dire 2 octets.

Cette fonction permute l’endianité d’un court-métrage.

Votre numéro commence à:

0001 0011 1000 1001 = 5001

Lorsque l’endianisme est modifié, il échange les deux octets:

1000 1001 0001 0011 = 35091

28
Salgar

la fonction htons() convertit les valeurs entre les ordres d'octets de l'hôte et du réseau. Il existe une différence entre big-endian et little-endian et l'ordre des octets du réseau, en fonction de votre machine et du protocole de réseau utilisé.

5
xingh1991

Il est fait pour maintenir la disposition des octets qui sont envoyés dans le réseau (Endianness). Selon l'architecture de votre appareil, les données peuvent être rangées dans la mémoire au format big endian ou au format little endian. Dans la mise en réseau, nous appelons la représentation de l'ordre des octets en tant qu'ordre des octets du réseau et dans notre hôte, cela s'appelle Ordre des octets de l'hôte. Tout l'ordre des octets du réseau est au format big endian. Si l'architecture de la mémoire de votre hôte est au format little endian, la fonction htons () devient une nécessité, mais dans le cas d'une architecture de mémoire au format big endian, ce n'est pas nécessaire. Vous pouvez trouver la finalité de votre ordinateur aussi par programmation de la manière suivante: ->

   int x = 1;
   if (*(char *)&x){
      cout<<"Little Endian"<<endl;
   }else{
      cout<<"Big Endian"<<endl;
   }

et décidons ensuite d'utiliser htons () ou non.Mais pour éviter la ligne ci-dessus, nous écrivons toujours htons () bien que cela ne change pas pour l'architecture de mémoire basée sur Big Endian.

2
Kenpachi Zaraki