一、网络字节序
(上图来自网络,侵删)
本次讨论以IP首部ip.h为例。
struct ip {
#if BYTE_ORDER == LITTLE_ENDIAN
u_char ip_hl:4, /* header length */
ip_v:4; /* version */
#endif
#if BYTE_ORDER == BIG_ENDIAN
u_char ip_v:4, /* version */
ip_hl:4; /* header length */
#endif
u_char ip_tos; /* type of service */
short ip_len; /* total length */
u_short ip_id; /* identification */
short ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
已知网络采用大端字节序。和实验室的JackYang讨论,我们得出结论,上图各个字段是从低地址向高地址排布的。比如源地址字段比目的地址字段的地址低,这样和struct ip中各个字段顺序是匹配的。所谓字节序是
针对某个字段的各个字节来说的。考虑下图的Flag与Fragment offset字段,它们合起来是ip.h中的16位
ip_id字段:
JackYang认为wireshark看到的大端顺序。如果是小端机,真实顺序是
Fragment offset字段13个bit0在低地址,Flag010(0x2)在高地址。
另一个证据是内核网络源码,如下:
注意到占2个字节的IP校验和(iph->check)在重新计算时需要先ntohs再htons。这样在x86小端机可以正确运行。
二、字节内比特序
看到ip.h源码中
ip_hl和ip_v的位置关系(header length与version的位置关系),一个困扰我很久的历史遗留问题浮现脑海:字节内的比特顺序应该也和大小端有关!
答案的确如此。x86为小端序,它采用LSB 0 bit numbering,故ip_v在
ip_hl之后。