我正在学习套接字编程,并且对我在学习材料中使用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()
?
问题:
为什么ntohs()
上没有使用htons()
和adr_inet.sin_family
?
注意到的网站没有解释为什么 ntohs()
或htons()
用于各自的示例中;它只是说“注意使用”所述功能。
我理解字节顺序,网络字节顺序是大端顺序。我的问题更多的是关于何时需要struct sockaddr_in
的网络与主机字节顺序的成员?在第二个代码示例中,.sin_port
在传递给bind()
之前设置为网络字节顺序。我可以看到以网络或主机字节顺序将数据传递给该函数的情况:bind()
是一个“网络相关”函数,所以它可能需要网络字节顺序的数据;另一方面bind()
在主机上执行,那么为什么不接受主机字节顺序的数据呢?
答案 0 :(得分:4)
为什么ntohs()在第一个实例中用于adr_inet.sin_port,而在第二个实例中用于htons()?
第一个是错误,但无论如何在实践中都有效。
现在几乎所有机器都使用8位字节和一致的big-endian或一致的little-endian格式。在前者hton[sl]
和ntoh[sl]
都是无操作;在后者两者反转字节顺序,因此实际上做同样的事情,即使他们的预期语义不同。因此,使用错误的程序仍然适用于您可能运行程序的所有系统。
当设计套接字API时,情况并非总是如此;例如当时流行的PDP-11在某种程度上臭名昭着地使用了'middle-endian'(!)又名为'NUXI'的32位命令。
为什么adr_inet.sin_family上既没有使用ntohs()也没有使用htons()?
在古代,互联网协议栈只是几种(多达十几种)竞争网络技术中的一种。 family
字段区分了这些不同协议的不同类型的sockaddr_*
结构,这些协议并不都遵循大端的互联网“规则”,至少不一致。由于family
没有通用网络表示,他们只是将其保留为主机顺序 - 这通常对主机软件更方便。
现在实际上没有人使用任何系列,只有INET,INET6,有时是UNIX - 后者可以通过在文件系统中使用命名管道来替换,通常至少同样好。
答案 1 :(得分:1)
为什么
ntohs()
上没有使用htons()
和adr_inet.sin_family
?
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 long
和unsigned short
转换函数的数据类型。因此,如果您有可能遇到从该网站运行代码的问题
你正在使用更新版本的C。