理解htonl()和ntohl()

oar*_*ish 9 c sockets networking endianness

我正在尝试使用unix套接字来测试向localhost发送一些udp数据包.

我的理解是,当设置IP地址和端口以便发送数据包时,我会将我sockaddr_in的值转换为网络字节顺序.我在OSX上,我对此感到惊讶

printf("ntohl: %d\n", ntohl(4711));
printf("htonl: %d\n", htonl(4711));
printf("plain: %d\n", 4711);
Run Code Online (Sandbox Code Playgroud)

打印

ntohl: 1729232896
htonl: 1729232896
plain: 4711
Run Code Online (Sandbox Code Playgroud)

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

相关代码是这样的:

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;
}
Run Code Online (Sandbox Code Playgroud)

dbu*_*ush 8

正如其他人所说,无论是htonsntohs扭转little-endian的机器上的字节顺序,并在大端机器空操作.

没有提到的是这些函数采用16位值并返回16位值.如果要转换32位值,则需要使用htonlntohl不是.

这些函数的名称来自某些数据类型的传统大小.的s代表short,而l代表long.A short通常为16位,而较旧的系统long为32位.

在代码中,你不需要调用htonlrec_addr,因为该值被返回inet_addr,和函数返回网络字节顺序地址.

然而,你需要调用htonsrec_port.


pm1*_*100 6

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

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

net, ie be, number = htonl / ntohl (le number)
Run Code Online (Sandbox Code Playgroud)

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

le num = htonl/ntohl (net ,ie be, number)
Run Code Online (Sandbox Code Playgroud)

在大型机器上

net, ie be, number = htonl / ntohl (be number)
Run Code Online (Sandbox Code Playgroud)

 be num = htonl/ntohl (net ,ie be, number)
Run Code Online (Sandbox Code Playgroud)

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

  • 即使这两个函数做同样的事情,对它们使用不同的名称仍然很有用,因为它阐明了代码的意图——即,如果我看到 x=ntohl(blah) 我知道分配给 x 的值在语义上是有意义的,而如果我看到 x=htonl(blah) 我知道 x 的值不是我可以依赖的本地端。如果代码只是 x=maybe_endian_swap(blah),那么我是否可以例如 printf("%i\n", x); 对我来说并不明显。之后,看到一个语义上有意义的值打印出来。 (8认同)
  • Endianness 不是起源的观点,而是目的地的观点:https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html (3认同)

Mic*_*ter 5

这两个函数都反转了字节的顺序.为什么会返回论证本身?

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

  • “反转字节”如果它们必须在您的系统上反转...您可以猜测它们两个或都不反转字节...取决于您的架构。 (3认同)

gud*_*dok 5

“网络字节顺序”始终表示大字节序。

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

因为Intel架构是低位优先的,所以这意味着两个功能都在做相同的事情:反转字节顺序。

  • “网络字节顺序”演变为_big endian_。并非总是这样。现在非常普遍。https://zh.wikipedia.org/wiki/Endianness#Networking (2认同)