在套接字编程中的 htons()函数

我是套接字编程的新手,我正在尝试理解 htons()的操作。我在互联网上读过一些教程,比如 这个这个。但我不能理解 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的。有人能解释一下价值变化的原因吗?

155725 次浏览

htonshost-to-network short

这意味着它适用于16位短整数,即2字节。

这个函数交换一个 short 的 endianness。

你的号码开头是:

0001 0011 1000 1001 = 5001

当 endianness 更改时,它将交换两个字节:

1000 1001 0001 0011 = 35091

htons()函数在主机和网络字节顺序之间转换值。Big-EndianLittle-Endian以及网络字节顺序之间存在差异,这取决于所使用的计算机和网络协议。

它与字节在内存中的存储顺序有关。十进制数字 5001是十六进制的 0x1389,因此所涉及的字节是 0x130x89。许多设备以 Little-Endian格式存储数字,这意味着最低有效字节优先。因此在这个特殊的例子中,它意味着在内存中,数字 5001将被存储为

0x89 0x13

htons()函数确保数字以网络字节顺序存储在内存中,网络字节顺序首先是最有意义的字节。因此,它将交换组成数字的字节,以便在内存中按顺序存储字节

0x13 0x89

Little-Endian机器上,带有交换字节的数字是十六进制的 0x8913,十进制的 35091。请注意,如果您使用的是 Big-Endian机器,那么 htons()函数将不需要进行任何交换,因为该数字已经以正确的方式存储在内存中。

所有这些交换的根本原因与正在使用的网络协议有关,这些协议要求传输的数据包使用网络字节顺序。

这样做是为了维护在网络中发送的字节的排列(endianness)。

根据设备的体系结构,数据可以以大端格式或小端格式排列在内存中。在网络中,我们称字节顺序的表示为网络字节顺序,在我们的主机中,它被称为主机字节顺序。所有网络字节顺序都是大端字节格式。

如果主机的内存计算机体系结构是小端点格式,那么就需要 htons()函数,但是如果是大端点格式的内存体系结构,则不需要 htons()函数。

你也可以通过以下方式用编程方式找到你的计算机的字节顺序:

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

然后决定是否使用 htons()。但是为了避免上面这一行,我们总是编写 htons(),尽管它对基于 big endian 的内存架构没有改变。

为了得到直接的术语,portno是一个 整数,而 sockaddr是一个 流动容器流动容器

当您通过网络发送数据时,您通过一种称为 序列化的机制将它们放入流中。在网络环境中,常见的规则是将数字按大 Endian 字节顺序排列,即整数类型的高值数字优先。如果您的处理器架构的内存布局也是 Big Endian,那么整数的内存表示将一个接一个地进入容器,否则字节顺序将被调整。这就是 htons所做的: 创建一个短的 int 值 sin_port,这样它的内存布局就符合意味着端口号的 Big Endian 表示法。