【问题标题】:struct sockaddr_in member byte order for bind()bind() 的 struct sockaddr_in 成员字节顺序
【发布时间】:2017-05-31 03:07:51
【问题描述】:

我正在学习套接字编程,我对我的学习材料中 htons() 和函数系列的使用不一致感到困惑。我目前正在阅读this site,它具有以下代码段:

001 1:       struct sockaddr_in adr_inet;
002 2:       int adr_len;
003 3:
004 4:       memset(&adr_inet,0,sizeof adr_inet);
005 5:
006 6:       adr_inet.sin_family = AF_INET;
007 7:       adr_inet.sin_port = ntohs(0);
008 8:       adr_inet.sin_addr.s_addr = ntohl(INADDR_ANY);
009 9:       adr_len = sizeof adr_inet;

在同一个著名站点的下一个示例具有以下代码段:

030 30:      struct sockaddr_in adr_inet;/* AF_INET */
...
042 42:      /* Create an AF_INET address */
043 43:      memset(&adr_inet,0,sizeof adr_inet);
044 44:
045 45:      adr_inet.sin_family = AF_INET;
046 46:      adr_inet.sin_port = htons(9000);
047 47:      memcpy(&adr_inet.sin_addr.s_addr,IPno,4);
048 48:      len_inet = sizeof adr_inet;
049 49:
050 50:      /* Now bind the address to the socket */
051 51:      z = bind(sck_inet,
052 52:          (struct sockaddr *)&adr_inet,
053 53:          len_inet);

问题

为什么ntohs()第一次用在adr_inet.sin_port上,而htons()用第二次?

问题

为什么adr_inet.sin_family 上既没有使用ntohs() 也没有使用htons()

注明的网站没有解释为什么 ntohs()htons() 在各自的示例中被使用;它只说“注意使用”所述功能。

我了解字节顺序,并且网络字节顺序是大端顺序。我的问题更多是关于您何时需要struct sockaddr_in 的网络成员与主机字节顺序?在第二个代码示例中,.sin_port 在传递给bind() 之前设置为网络字节顺序。我可以看到以网络或主机字节顺序将数据传递给该函数的情况:bind() 是一个“网络相关”函数,因此它可能需要以网络字节顺序的数据;另一方面bind()是在主机上执行的,那为什么不接受主机字节序的数据呢?

【问题讨论】:

  • ((我建议你阅读getaddrinfo() 以编写更现代的C))

标签: c sockets endianness


【解决方案1】:

为什么adr_inet.sin_port第一次用ntohs(),第二次用htons()?

第一个是错误的,但实际上仍然有效。

现在几乎所有机器都使用 8 位字节和一致的大端或一致的小端格式。在前者上,hton[sl]ntoh[sl] 都是无操作的;在后者 both 上,颠倒了字节顺序,因此即使它们的预期语义不同,实际上也会做同样的事情。因此,使用错误的系统仍然适用于您可能运行程序的所有系统。

在设计套接字 API 时,情况并非总是如此;例如当时流行的 PDP-11 有点臭名昭著地使用 'middle-endian' (!) aka 'NUXI' order for 32-bit。

为什么在 adr_inet.sin_family 上既没有使用 ntohs() 也没有使用 htons()?

在古代,互联网协议栈只是几种(多达十几种)相互竞争的网络技术中的一种。 family 字段为这些不同的协议区分不同类型的sockaddr_* 结构,它们并不都遵循互联网大端的“规则”,至少不一致。由于family 没有通用的网络表示,他们只是将其保留在主机顺序中——这对于主机软件来说通常更方便。

现在实际上除了 INET、INET6 和有时 UNIX 之外没有人使用任何家族——而后者可以通过在文件系统中使用命名管道来替换,这通常至少同样好。

【讨论】:

  • 啊:我误解了hton[sl]ntoh[sl]:我以为他们保证输出分别是网络或主机字节排序的。但是当我想到它时,那是不可能实现的,所以这些函数唯一能做的就是根据架构做出决定是无操作还是字节交换。
  • UNIX 套接字绝对不能被命名管道替代。首先,一个命名管道只能有一个命名连接。而且 AFAIK 你不能通过命名管道发送辅助数据(文件描述符)。
【解决方案2】:

为什么adr_inet.sin_family 上既没有使用ntohs() 也没有使用htons()

adr_inet.sin_family 被初始化为AF_INET 的值。这在bits/socket.h(在您的示例中由netinet/in.h 调用)中定义为:

#define PF_INET     2   /* IP protocol family.  */

然后,

#define AF_INET     PF_INET

所以AF_INET 只是程序将关联的套接字识别为 TCP/IP 连接的一种方式。它实际上并不保存 IPv4 地址本身的值,因此无需对其执行字节序转换。

另外,请注意,在 C 的较新迭代中,netinet/in.h 有一条注释说明如下:

/* Functions to convert between host and network byte order.

   Please note that these functions normally take `unsigned long int' or
`unsigned short int' values as arguments and also return them.  But
this was a short-sighted decision since on different systems the types
may have different representations but the values are always the same.  */ 
extern uint32_t ntohl (uint32_t __netlong) __THROW __attribute__ ((__const__));
extern uint16_t ntohs (uint16_t __netshort)
        __THROW __attribute__ ((__const__));
extern uint32_t htonl (uint32_t __hostlong)
        __THROW __attribute__ ((__const__));
extern uint16_t htons (uint16_t __hostshort)
        __THROW __attribute__ ((__const__));

而您引用的网站引用了 unsigned longunsigned short 的旧用法 转换函数的数据类型。因此,如果您从该站点运行代码,您可能会遇到问题 您使用的是较新版本的 C。

【讨论】:

  • 即使在具有 64 位 unsigned long 的系统上,如果您只使用底部 32 位,存储到 uint32_t 或从 uint32_t 存储也可以。在最坏的情况下,您可能会收到有关缩小隐式转换的警告。
  • 是的,你完全正确。我应该在我的帖子中更清楚地说明这一点。尽管如此,在这种情况下,这些数据类型的使用可能被认为有点过时了。或者正如作者在较新的转换原型上方的评论中所写的那样“短视”。
  • 是的。历史上的 Unix API 通过假设 unsigned long 是保存指针、文件偏移量、自 1970 年以来的秒数等的正确长度而产生了很多问题——而且它的长度正好是 32 位。如今,大多数编译器让您选择其中一个假设应该是正确的,并且 POSIX 保证有一个编译器标志可以使 long 足够宽以容纳任何这些类型。但最好使用你真正想要的类型。
  • 哦,对后来出现的任何人的补充说明:要获得现代定义,请在包含系统标头之前设置一个功能测试宏,例如 POSIX 上的_XOPEN_SOURCE 和/或_POSIX_C_SOURCE /Linux/glibc 或 Windows 上的 _WIN32_WINNT。这些改变了头文件中哪些声明处于活动状态。
猜你喜欢
  • 1970-01-01
  • 2015-06-21
  • 1970-01-01
  • 2020-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多