内核源码-/include/net/inet_sock.h
1. 网络序与字节序:
inet_sock.h
比较值得关注的内容是inet_sock
:
1 |
|
首先我们注意到有inet_num
和inet_sport
两个字段,并且前者表示Local Port,后者表示Source Port。那二者有何区别?这里StackOverflow上有一个相关回答:https://stackoverflow.com/questions/55313362/what-is-the-difference-between-local-port-and-source-port-in-inet-sock-h-in
其大意是:
inet_num
是Local port in host byte-order / protocol type
,而inet_sport
是The source port in network byte-order. This is the port you see in packet.
这就又涉及到一个网络字节序和主机字节序问题的讨论。这里有一篇相关博客:https://blog.csdn.net/lxj434368832/article/details/78499937。
1.1 网络字节序(Network Byte Order, NBO)和主机字节序(Host Byte Order, HBO)
Linux man page中提到,arpa/inet.h
中定义了四个函数:
1 |
|
函数 | 作用 |
---|---|
htonl | 将uint32_t 类型的HBO地址 转为NBO地址 |
htons | 将uint16_t 类型的HBO地址 转为NBO地址 |
ntohl | 将uint32_t 类型的NBO地址 转为HBO地址 |
ntohs | 将uint16_t 类型的NBO地址 转为HBO地址 |
Linux提供了相关的转换函数,了解NBO和HBO区别之前,我们再明确一下大端/小端的基本概念。沿着内存增大的方向,如果一个数据的的开始字节(一般也叫做Least Significant Byte, LSB最低有效字节)放在低地址,而结束字节(一般也叫做Most Significant Byte, MSB最高有效字节)放在高地址,则称这种数据存放方式为小端(little-endian)字节序,反之则称为大端(big-endian)字节序。简而言之:数据的初始字节放在低地址就是小端,放在高地址就是大端。具体如下图所述:
注意:字节序只是字节的排列顺序不同,但对应的字节内部的8位二进制数顺序都是一样的~
UDP/TCP/IP协议规定:把接收到的第一个字节当作高位字节看待。因此网络字节序统一都是大端字节序。而不同主机的字节序各有不同,为了保证网络通信时数据传输的一致性,就需要有NBO和HBO之间的相互转化。