Linux中iphdr、tcphdr结构体的

您所在的位置:网站首页 iphdr结构体 Linux中iphdr、tcphdr结构体的

Linux中iphdr、tcphdr结构体的

2023-10-15 16:13| 来源: 网络整理| 查看: 265

代码

在/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