C语言 理解 htonl() 和 ntohl()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36924598/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 10:24:32  来源:igfitidea点击:

Understanding htonl() and ntohl()

csocketsnetworkingendianness

提问by oarfish

I am trying to use unix sockets to test sending some udp packets to localhost.

我正在尝试使用 unix 套接字来测试向本地主机发送一些 udp 数据包。

It is my understanding that when setting ip address and port in order to send packets, I would fill my sockaddr_inwith values converted to network-byte order. I am on OSX and I'm astonished that this

我的理解是,在设置 ip 地址和端口以发送数据包时,我会sockaddr_in用转换为网络字节顺序的值填充我的值。我在 OSX 上,我很惊讶这

printf("ntohl: %d\n", ntohl(4711));
printf("htonl: %d\n", htonl(4711));
printf("plain: %d\n", 4711);

Prints

印刷

ntohl: 1729232896
htonl: 1729232896
plain: 4711

So neither function actually returns the plain value. I would have expected to see either the results differ, as x86 is little-endian (afaik), or be identical and the same as the actual number 4711. Clearly I do not understand what htonland ntohland their variants do. What am I missing?

所以这两个函数实际上都没有返回普通值。我本来期望看到任何结果不同,因为86是小端(据我所知),或者是相同的,同为实际数量4711显然,我不明白是什么htonlntohl及其变种做。我错过了什么?

The relevant code is this:

相关代码是这样的:

int main(int argc, char *argv[])
{
   if (argc != 4)
   {
      fprintf(stderr, "%s\n", HELP);
      exit(-1);
   }

   in_addr_t rec_addr = inet_addr(argv[1]); // first arg is '127.0.0.1'
   in_port_t rec_port = atoi(argv[2]);      // second arg is port number
   printf("Address is %s\nPort is %d\n", argv[1], rec_port);
   char* inpath = argv[3];

   char* file_buf;
   unsigned long file_size = readFile(inpath, &file_buf); // I am trying to send a file
   if (file_size > 0)
   {
      struct sockaddr_in dest;
      dest.sin_family      = AF_INET;
      dest.sin_addr.s_addr = rec_addr; // here I would use htons
      dest.sin_port        = rec_port;
      printf("ntohs: %d\n", ntohl(4711));
      printf("htons: %d\n", htonl(4711));
      printf("plain: %d\n", 4711);
      int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
      if (socket_fd != -1)
      {
         int error;
         error = sendto(socket_fd, file_buf, file_size + 1, 0, (struct sockaddr*)&dest, sizeof(dest));
         if (error == -1)
            fprintf(stderr, "%s\n", strerror(errno));
         else printf("Sent %d bytes.\n", error);
      }
   }

   free(file_buf);
   return 0;
}

采纳答案by Michel de Ruiter

Both functions reverse the bytes' order. Why would that return the argument itself?

这两个函数都反转字节的顺序。为什么会返回参数本身?

Try htons(ntohs(4711))and ntohs(htons(4711)).

尝试htons(ntohs(4711))ntohs(htons(4711))

回答by dbush

As others have mentioned, both htonsand ntohsreverse the byte order on a little-endian machine, and are no-ops on big-endian machines.

正如其他人所提到的,htons和都ntohs在小端机器上反转字节顺序,并且在大端机器上是无操作的。

What wasn't mentioned is that these functions take a 16-bit value and return a 16-bit value. If you want to convert 32-bit values, you want to use htonland ntohlinstead.

没有提到的是这些函数采用 16 位值并返回一个 16 位值。如果要转换 32 位值,则要使用htonlandntohl代替。

The names of these functions come from the traditional sizes of certain datatypes. The sstands for shortwhile the lstands for long. A shortis typically 16-bit while on older systems longwas 32-bit.

这些函数的名称来自某些数据类型的传统大小。该s代表short同时l表示long。Ashort通常为 16 位,而在较旧的系统上long为 32 位。

In your code, you don't need to call htonlon rec_addr, because that value was returned by inet_addr, and that function returns the address in network byte order.

在您的代码中,您不需要调用htonlon rec_addr,因为该值由 返回inet_addr,并且该函数以网络字节顺序返回地址。

You do however need to call htonson rec_port.

然而,你需要调用htonsrec_port

回答by gudok

"Network byte order" always means big endian.

“网络字节顺序”总是意味着大端。

"Host byte order" depends on architecture of host. Depending on CPU, host byte order may be little endian, big endian or something else. (g)libc adapts to host architecture.

“主机字节顺序”取决于主机的架构。根据 CPU 的不同,主机字节顺序可能是小端、大端或其他。(g)libc 适应主机架构。

Because Intel architecture is little endian, this means that both functions are doing the same: reversing byte order.

因为英特尔架构是小端的,这意味着两个函数都在做同样的事情:反转字节顺序。

回答by pm100

these functions are poorly named. Host to networkand network to hostare actually the same thing and really should be called 'change endianness if this is a little endian machine'

这些函数命名不当。Host to network并且network to host实际上是同一件事,真的应该称为“如果这是一个小字节序机器,则更改字节序”

So on a little endian machine you do

所以在一个小端机器上你做

net, ie be, number = htonl / ntohl (le number)

and send the be number on the wire. And when you get a big endian number from the wire

并在电线上发送 be 号码。当你从电线上得到一个大端数字时

le num = htonl/ntohl (net ,ie be, number)

on a big end machine

在大型机器上

net, ie be, number = htonl / ntohl (be number)

and

 be num = htonl/ntohl (net ,ie be, number)

and in the last cases you see that these functions do nothing

在最后一种情况下,你会看到这些函数什么都不做