67

我是套接字编程的新手,我正在尝试了解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在调试时,我不明白如何portno从 更改500135091。有人可以解释一下价值变化的原因吗?

4

5 回答 5

137

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

0x89 0x13

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

0x13 0x89

little-endian机器上,交换字节的数字是0x8913十六进制的,即35091十进制表示法。请注意,如果您在大端机器上工作,则该htons()函数不需要进行任何交换,因为该数字已经以正确的方式存储在内存中。

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

于 2013-10-06T13:40:34.683 回答
45

htonshost-to-network short

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

此函数交换短的字节序。

您的号码开始于:

0001 0011 1000 1001 = 5001

当字节序改变时,它交换两个字节:

1000 1001 0001 0011 = 35091

于 2013-10-06T10:35:46.543 回答
8

htons()函数在主机和网络字节顺序之间转换值。big-endianlittle-endian以及网络字节顺序之间存在差异,具体取决于您的机器和使用的网络协议。

于 2013-10-06T10:43:33.310 回答
5

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

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

如果您的主机的内存计算机架构是小端格式,则该htons()功能变得必要,但在大端格式内存架构的情况下,则没有必要。

您也可以通过以下方式以编程方式查找计算机的字节序:

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

然后决定是否使用htons()。但是为了避免上面的行,我们总是写htons()虽然它对基于大端的内存架构没有任何变化。

于 2018-11-03T20:25:41.870 回答
0

为了让术语直截了当,portno是一个整数,并且sockaddr是一个流式容器

当您通过网络发送数据时,您通过一种称为序列化的机制将它们放入流中。在网络环境中,常见的规则是将数字按 Big Endian 字节顺序排列,即整数类型的高值数字先出现。如果你的处理器架构的内存布局也是Big Endian,那么整数的内存表示会一一传递给容器,否则字节顺序应该调整。这就是这样htons做的:创建一个短的 int 值sin_port,这样它的内存布局就可以满足平均端口号的 Big Endian 表示。

于 2021-05-25T13:53:07.770 回答