Linux中iphdr、tcphdr结构体的 |
您所在的位置:网站首页 › iphdr结构体 › Linux中iphdr、tcphdr结构体的 |
代码
在/usr/include/uapi/linux/ip.h和/usr/include/uapi/linux/tcp.h中分别有如下代码定义了ip以及tcp头部 iphdr: struct iphdr { #if defined(__LITTLE_ENDIAN_BITFIELD) __u8 ihl:4, version:4; #elif defined (__BIG_ENDIAN_BITFIELD) __u8 version:4, ihl:4; #else #error "Please fix " #endif __u8 tos; __be16 tot_len; __be16 id; __be16 frag_off; __u8 ttl; __u8 protocol; __sum16 check; __be32 saddr; __be32 daddr; /*The options start here. */ };tcphdr: struct tcphdr { __u16 source; __u16 dest; __u32 seq; __u32 ack_seq; #if defined(__LITTLE_ENDIAN_BITFIELD) __u16 res1:4, doff:4, fin:1, syn:1, rst:1, psh:1, ack:1, urg:1, ece:1, cwr:1; #elif defined(__BIG_ENDIAN_BITFIELD) __u16 doff:4, res1:4, cwr:1, ece:1, urg:1, ack:1, psh:1, rst:1, syn:1, fin:1; #else #error "Adjust your defines" #endif __u16 window; __u16 check; __u16 urg_ptr; };这其中:4等是C语言中的位域,表示取二进制中的低四位(在大端序中这个低四位是存储在高地址的)。 疑问初读这些代码,我还并不理解为何有大小端的区别,"big endian"和"little endian"的区别是在按字节之间的存储顺序上。比如0x12345678 在"little endian"上表示为(假设基址为0x100): 0x100 0x78 (01111000) 0x101 0x56 0x102 0x34 0x103 0x12 在“big endian"上表示为: 0x100 0x12 0x101 0x34 0x102 0x56 0x103 0x78 (01111000) 显然对单个字节来说,其中的位存储还是相同的,所以我并不理解为何在Linux的代码中,要把它们一些字节的位域定义成相反的顺序。 解答经过我搜集资料后终于找到了答案: 譬如ip头部ip_hdr,假设仅仅是直接对ihl或者version进行操作,确实无需分辨大小端字节序,Linux代码中那样写反而有些多此一举。 但使用者可能使用memcpy来直接对这开头的8位进行赋值操作,而这在大端序和小端序的机器上会产生不同的情况。 举个经典的例子,比如说下述代码: u_int16_t t = 0x1; u_int8_t x[2]; memcpy(x, t);在小端序的机器上结果应该是 x[0] x[1] 10 … 00 而在大端序的机器上执行结果会变为: x[0] x[1] 00 … 01 注:x[1]的地址都是比x[0]高的。 因此为了提高兼容性,使程序能够被小端序和大端序的机器共用。须要预先推断是大端序还是小端序。并调换ihr和version在内存中的位置。 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |