ソケットプログラミングは初めてで、htons()
の操作を理解しようとしています。 this や this など、インターネットでいくつかのチュートリアルを読みました。しかし、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
として表示されましたが、portno
が5001
から35091
に変更された方法がわかりません。誰かがその価値の変化の理由を説明してもらえますか?
これは、メモリにバイトが格納される順序に関係しています。 10進数5001
は16進数の0x1389
であるため、関係するバイトは0x13
および0x89
です。多くのデバイスは、数字をリトルエンディアン形式で保存します。つまり、最下位バイトが最初に来ます。したがって、この特定の例では、メモリ内に5001
という数値が次のように格納されることを意味します。
0x89 0x13
htons()
関数は、数値がネットワークバイト順でメモリに格納されるようにします。これは、最上位バイトが最初になります。したがって、番号を構成するバイトをスワップして、メモリにバイトが順番に格納されるようにします
0x13 0x89
リトルエンディアンマシンでは、スワップされたバイトの数は、16進数で0x8913
、10進数で35091
です。 ビッグエンディアンマシンで作業している場合、htons()
関数は、番号が既にメモリに正しい方法で格納されているため、スワッピングを行う必要がないことに注意してください。
このすべてのスワッピングの根本的な理由は、使用中のネットワークプロトコルに関係しているため、送信されたパケットがネットワークバイトオーダーを使用する必要があります。
htons
はHost-to-network short
です
これは、16ビットの短整数で機能することを意味します。つまり、2バイト。
この関数は、ショートのエンディアンを交換します。
番号は次の場所から始まります:
0001 0011 1000 1001 = 5001
エンディアンが変更されると、2バイトがスワップされます。
1000 1001 0001 0011 = 35091
htons()
関数は、ホストとネットワークのバイト順の間で値を変換します。 big-endianとlittle-endianには違いがあり、使用しているマシンとネットワークプロトコルに応じてネットワークバイトオーダーが異なります。
ネットワークで送信されるバイトの配置を維持するために行われます(エンディアンネス)。デバイスのアーキテクチャに応じて、ビッグエンディアン形式またはリトルエンディアン形式のいずれかでデータをメモリに配置できます。ネットワークでは、バイトオーダーの表現をネットワークバイトオーダーと呼び、ホストではホストバイトオーダーと呼びます。すべてのネットワークバイトオーダーはビッグエンディアン形式です。ホストのメモリコンピュータアーキテクチャがリトルエンディアン形式の場合、htons()関数が必要になりますが、ビッグエンディアン形式のメモリアーキテクチャの場合は必要ありません。コンピュータのエンディアンを確認できます。次の方法でもプログラム的に:->
int x = 1;
if (*(char *)&x){
cout<<"Little Endian"<<endl;
}else{
cout<<"Big Endian"<<endl;
}
そして、htons()を使用するかどうかを決定します。しかし、上記の行を避けるために、Big Endianベースのメモリアーキテクチャには変更を加えませんが、常にhtons()を記述します。