web-dev-qa-db-ja.com

ソケットプログラミングのhtons()関数

ソケットプログラミングは初めてで、htons()の操作を理解しようとしています。 thisthis など、インターネットでいくつかのチュートリアルを読みました。しかし、htons()が正確に何をするのか理解できませんでした。私は次のコードを試しました:

#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; 
}

sin_portの値は、デバッグ中に35091として表示されましたが、portno5001から35091に変更された方法がわかりません。誰かがその価値の変化の理由を説明してもらえますか?

40
User123422

これは、メモリにバイトが格納される順序に関係しています。 10進数5001は16進数の0x1389であるため、関係するバイトは0x13および0x89です。多くのデバイスは、数字をリトルエンディアン形式で保存します。つまり、最下位バイトが最初に来ます。したがって、この特定の例では、メモリ内に5001という数値が次のように格納されることを意味します。

0x89 0x13

htons()関数は、数値がネットワークバイト順でメモリに格納されるようにします。これは、最上位バイトが最初になります。したがって、番号を構成するバイトをスワップして、メモリにバイトが順番に格納されるようにします

0x13 0x89

リトルエンディアンマシンでは、スワップされたバイトの数は、16進数で0x8913、10進数で35091です。 ビッグエンディアンマシンで作業している場合、htons()関数は、番号が既にメモリに正しい方法で格納されているため、スワッピングを行う必要がないことに注意してください。

このすべてのスワッピングの根本的な理由は、使用中のネットワークプロトコルに関係しているため、送信されたパケットがネットワークバイトオーダーを使用する必要があります。

93
brm

htonsHost-to-network shortです

これは、16ビットの短整数で機能することを意味します。つまり、2バイト。

この関数は、ショートのエンディアンを交換します。

番号は次の場所から始まります:

0001 0011 1000 1001 = 5001

エンディアンが変更されると、2バイトがスワップされます。

1000 1001 0001 0011 = 35091

28
Salgar

htons()関数は、ホストとネットワークのバイト順の間で値を変換します。 big-endianlittle-endianには違いがあり、使用しているマシンとネットワークプロトコルに応じてネットワークバイトオーダーが異なります。

5
xingh1991

ネットワークで送信されるバイトの配置を維持するために行われます(エンディアンネス)。デバイスのアーキテクチャに応じて、ビッグエンディアン形式またはリトルエンディアン形式のいずれかでデータをメモリに配置できます。ネットワークでは、バイトオーダーの表現をネットワークバイトオーダーと呼び、ホストではホストバイトオーダーと呼びます。すべてのネットワークバイトオーダーはビッグエンディアン形式です。ホストのメモリコンピュータアーキテクチャがリトルエンディアン形式の場合、htons()関数が必要になりますが、ビッグエンディアン形式のメモリアーキテクチャの場合は必要ありません。コンピュータのエンディアンを確認できます。次の方法でもプログラム的に:->

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

そして、htons()を使用するかどうかを決定します。しかし、上記の行を避けるために、Big Endianベースのメモリアーキテクチャには変更を加えませんが、常にhtons()を記述します。

2
Kenpachi Zaraki