Sto*_*row 0 c sockets endianness
我正在学习套接字编程,并且对我认为htons()在我的学习材料中使用不一致的函数系列感到困惑。我目前正在阅读这个网站,它有以下代码段:
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;
Run Code Online (Sandbox Code Playgroud)
位于同一站点的后续示例具有以下代码段:
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);
Run Code Online (Sandbox Code Playgroud)
问题:
为什么在第一种情况下ntohs()使用 on adr_inet.sin_port,而htons()在第二种情况下使用?
问题:
为什么既不使用ntohs()也不htons()使用adr_inet.sin_family?
提到的站点没有解释为什么 ntohs()或htons()在各自的示例中使用;它只说“注意使用”所述功能。
我理解字节序并且网络字节顺序是大端顺序。我的问题更多是关于什么时候需要 astruct sockaddr_in的成员在网络与主机字节顺序中?在第二个代码示例中,.sin_port在传递给 之前设置为网络字节顺序bind()。我可以看到以网络或主机字节顺序将数据传递给此函数的情况:bind()是一个“与网络相关”的函数,所以它可能需要网络字节顺序的数据;另一方面bind()是在主机上执行的,那么为什么不应该以主机字节顺序接受数据呢?
为什么 ntohs() 在第一个实例中用于 adr_inet.sin_port,而在第二个实例中用于 htons()?
第一个是错误的,但在实践中无论如何都有效。
现在几乎所有的机器都使用 8 位字节和一致的大端或一致的小端格式。在前者上,hton[sl]和ntoh[sl]都是空操作;后者都颠倒了字节顺序,因此即使它们的预期语义不同,实际上也做同样的事情。因此,使用错误的方法仍然适用于您可能运行程序的所有系统。
回到设计套接字 API 时,情况并非总是如此;例如,当时流行的 PDP-11 有点臭名昭著地使用了'middle-endian' (!) aka 'NUXI' order for 32-bit。
为什么在 adr_inet.sin_family 上既不使用 ntohs() 也不使用 htons()?
同样在古代,互联网协议栈只是几种(多达十几种)相互竞争的网络技术之一。该family字段区分sockaddr_*了这些不同协议的不同类型的结构,这些结构并非都遵循大端的互联网“规则”,至少不是一致的。由于没有通用的网络表示,family他们只是将其保留在主机顺序中——这对于主机软件来说通常更方便。
现在在实践中,除了 INET、INET6 和有时 UNIX 之外,没有人使用任何家族——后者可以通过在文件系统中使用命名管道来代替,这通常至少是一样好的。