简体   繁体   English

struct sockaddr_in bind()的成员字节顺序

[英]struct sockaddr_in member byte order for bind()

I'm learning socket programming and am confused by what I feel is inconsistent use of htons() and family of functions in my learning material. 我正在学习套接字编程,对我在学习资料中对htons()和函数族的用法不一致感到困惑。 I'm currently reading this site which has the following code segment: 我目前正在阅读该网站 ,其中包含以下代码段:

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;

A subsequent example further down at the same noted site has the following code segment: 在相同注释站点上的后续示例具有以下代码段:

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);

Question : 问题

Why is ntohs() used on adr_inet.sin_port in the first instance, but htons() in the second? 为什么在第一个实例中在adr_inet.sin_port上使用ntohs() ,而在第二个实例中使用htons()

Question : 问题

Why is neither ntohs() nor htons() used on adr_inet.sin_family ? 为什么在adr_inet.sin_family上既不使用ntohs()也不使用htons()

The noted site doesn't explain why ntohs() or htons() are used in their respective examples; 提到的站点没有解释为什么在各自的示例中使用ntohs()htons() it only says to "note the use of" said functions. 它只是说要“注意”所述功能的使用。

I understand endianness and that network byte order is big-endian order. 我了解字节序,并且网络字节顺序是大字节序。 My questions is more about when do you want a struct sockaddr_in 's members in network vs. host byte order? 我的问题是关于何时需要网络中的struct sockaddr_in成员与主机字节顺序有关? In the second code example, .sin_port is set to network byte order before being passed to bind() . 在第二个代码示例中,将.sin_port设置为网络字节顺序,然后.sin_port bind() I can see the case for passing data to this function in either network or host byte order: bind() is a "network-related" function, so maybe it needs its data in network byte order; 我可以看到以网络或主机字节顺序将数据传递给此函数的情况: bind()是一个“与网络相关的”函数,因此它可能需要以网络字节顺序进行数据传递。 on the other hand bind() is executed on the host, so why shouldn't accept data in host byte order? 另一方面bind()是在主机上执行的,为什么不接受主机字节顺序的数据呢?

Why is ntohs() used on adr_inet.sin_port in the first instance, but htons() in the second? 为什么在第一个实例中在adr_inet.sin_port上使用ntohs(),而在第二个实例中使用htons()?

The first is a mistake, but in practice works anyway. 首先是一个错误,但在实践中还是可行的。

Nowadays practically all machines use 8-bit bytes and either consistent big-endian or consistent little-endian formats. 如今,几乎所有机器都使用8位字节以及一致的big-endian或一致的little-endian格式。 On the former both hton[sl] and ntoh[sl] are no-ops; 在前一种情况下, hton[sl]ntoh[sl]均为禁止操作; on the latter both reverse the byte order, and thus actually do the same thing even though their intended semantics are different. 后者颠倒了字节顺序,因此即使它们的预期语义不同,它们实际上也会做同样的事情。 Thus using the wrong one still works on all systems you're likely to run a program on. 因此,使用错误的代码仍然可以在您可能在其上运行程序的所有系统上使用。

Back when the socket API was designed this wasn't always the case; 回到设计套接字API时,情况并非总是如此。 for example the then-popular PDP-11 somewhat infamously used 'middle-endian' (!) aka 'NUXI' order for 32-bit. 例如,当时流行的PDP-11有点臭名昭著地使用32位的“中端” (!)或“ NUXI”顺序。

Why is neither ntohs() nor htons() used on adr_inet.sin_family? 为什么在adr_inet.sin_family上既不使用ntohs()也不使用htons()?

Again in ancient times the Internet Protocol stack was only one of several (up to a dozen or so) competing network technologies. 同样,在远古时代,Internet协议栈只是几种(最多十几种)竞争性网络技术中的一种。 The family field distinguishes different types of sockaddr_* structures for these different protocols, which did not all follow the Internet 'rule' for big-endian, at least not consistently. family字段针对这些不同的协议区分了不同类型的sockaddr_*结构,对于大端字节序,它们并非都遵循互联网的“规则”,至少是不一致的。 As there was no universal network representation for family they just left it in host order -- which is usually more convenient for host software. 由于没有针对family通用网络表示形式,因此他们只按主机顺序放置它-通常对于主机软件更方便。

Nowadays in practice nobody uses any families but INET, INET6, and sometimes UNIX -- and the latter can be replaced by using named pipes in the filesystem which is usually at least as good. 如今,在实践中,除了INET,INET6和UNIX以外,没有人使用任何族-可以通过在文件系统中使用命名管道来代替后者,通常至少是一样好。

Why is neither ntohs() nor htons() used on adr_inet.sin_family ? 为什么在adr_inet.sin_family上既不使用ntohs()也不使用htons()

adr_inet.sin_family is initialized to the value of AF_INET . adr_inet.sin_family初始化为AF_INET的值。 This is defined in bits/socket.h (which is called by netinet/in.h in your example) as: bits/socket.h (在您的示例中为netinet/in.h调用)中定义为:

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

and then, 接着,

#define AF_INET     PF_INET

So AF_INET is just a way for the program to identify the associated socket as a TCP/IP connection. 因此, AF_INET只是程序将关联套接字标识为TCP / IP连接的一种方式。 It won't actually hold the value of an IPv4 address itself, so there's no need to perform an endian conversion on it. 它实际上并不会保存IPv4地址的值,因此无需对其进行字节序转换。

Also, note that in newer iterations of C, netinet/in.h has a comment that states the following: 另外,请注意,在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__));

Whereas the website you're referencing cites the older use of unsigned long and unsigned short datatypes for the conversion functions. 而您所引用的网站引用了unsigned longunsigned short数据类型在转换函数中的较早使用。 So there's a chance you may encounter issues running code from that site if you're using a newer version of C. 因此,如果您使用的是较新版本的C,则有可能在该站点上运行代码时遇到问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM