我是socket编程的新手,我正在尝试理解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
的方式。有人可以解释价值变化的原因吗?
答案 0 :(得分:91)
它与字节存储在内存中的顺序有关。十进制数5001
以十六进制为0x1389
,因此所涉及的字节为0x13
和0x89
。许多设备以 little-endian 格式存储数字,这意味着最低有效字节首先出现。所以在这个特定的例子中,它意味着在内存中数字5001
将被存储为
0x89 0x13
htons()
函数确保数字以网络字节顺序存储在内存中,这首先是最重要的字节。因此,它将交换组成数字的字节,以便在内存中字节将按顺序存储
0x13 0x89
在 little-endian 计算机上,交换字节的数字为十六进制0x8913
,十进制表示法为35091
。请注意,如果您正在使用 big-endian 计算机,则htons()
函数不需要进行任何交换,因为该数字已经以正确的方式存储在内存中。
所有这些交换的根本原因与使用的网络协议有关,这需要传输的数据包使用网络字节顺序。
答案 1 :(得分:28)
htons
是host-to-network short
这意味着它适用于16位短整数。即2个字节。
此函数交换短线的字节序。
您的电话号码始于:
0001 0011 1000 1001 = 5001
当更改字节顺序时,它会交换两个字节:
1000 1001 0001 0011 = 35091
答案 2 :(得分:5)
htons()
函数在主机和网络字节顺序之间转换值。 big-endian 和 little-endian 与网络字节顺序有所不同,具体取决于您使用的计算机和网络协议。
答案 3 :(得分:2)
这样做是为了维护在网络中发送的字节的排列(字节序)。根据设备的体系结构,数据可以以大字节序格式或小字节序格式排列在内存中。在网络中,我们将字节顺序的表示形式称为网络字节顺序,在我们的主机中,它称为主机字节顺序。所有网络字节顺序均为大字节序格式。如果主机的内存计算机体系结构为小字节序格式,则必须使用htons()函数,但对于大字节序的内存体系结构则没有必要。您可以找到计算机的字节序也可以通过以下方式进行编程:->
int x = 1;
if (*(char *)&x){
cout<<"Little Endian"<<endl;
}else{
cout<<"Big Endian"<<endl;
}
然后决定是否使用htons()。但是为了避免出现上述情况,我们始终编写htons(),尽管它对于基于Big Endian的内存体系结构没有任何改变。
答案 4 :(得分:0)
为了清楚起见,portno
是一个整数,而 sockaddr
是一个流容器。
当您通过网络发送数据时,您通过一种称为序列化的机制将它们放入流中。在网络环境中,常见的规则是将数字按 Big Endian 字节顺序排列,即整数类型的较高值数字在前。如果您的处理器架构的内存布局也是 Big Endian,那么整数的内存表示会一个一个地传递到容器中,否则将调整字节顺序。这就是 htons
所做的:创建一个短 int 值 sin_port
,这样它的内存布局就可以满足大端端口号的表示。