理解htonl()和ntohl()

时间:2016-04-28 20:11:41

标签: 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);

打印

ntohl: 1729232896
htonl: 1729232896
plain: 4711

因此,两个函数都没有实际返回普通值。我希望看到结果不同,因为x86是little-endian(afaik),或者与实际数字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;
}

4 个答案:

答案 0 :(得分:7)

正如其他人所提到的,htonsntohs都反转了little-endian机器上的字节顺序,并且在big-endian机器上都是no-ops。

未提及的是这些函数采用16位值并返回16位值。如果要转换32位值,则需要使用htonlntohl

这些函数的名称来自某些数据类型的传统大小。 s代表shortl代表longshort通常为16位,而旧系统long为32位。

在您的代码中,您无需在htonl上调用rec_addr,因为该值由inet_addr返回,并且该函数以网络字节顺序返回地址。 / p>

但您需要在htons上致电rec_port

答案 1 :(得分:5)

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

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

答案 2 :(得分:4)

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

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

由于英特尔架构是小端,这意味着两个函数都在相同:颠倒字节顺序。

答案 3 :(得分:2)

这些功能名称不佳。 Host to networknetwork to host实际上是同一个东西,如果这是一个小端机器,它应该被称为'更改字节序'

所以在你做的小端机器上

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

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

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

在一台大型机器上

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

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

在最后一种情况下,您会看到这些功能无效