open-iscsi/scst 追踪四(网络字节序)(转载有修改)

来源:互联网 发布:java 趣味题 编辑:程序博客网 时间:2024/05/22 03:07

字节序问题 --- Endianness

1.1.      Processers

所有的字节序问题都要追踪到CPU上,不管是GeneralCPU 还是 Special CPU ,CPU决定了存储的字节排列顺序问题,即字节序(Endianness)。

通用CPU领域以intel代表的x86家族历来以little-endian为主,而POWER-PC则主推big-endian设计的CPU;对于SpecialCPU,特别是在嵌入式领域,如网卡上的嵌入式微处理器,存储控制器上的嵌入式微处理器,基本采用了big-endian的设计。所以出现了两种定义说法:主机字节序(host-endianness)和网络字节序(net-endianness)。

1.2.数据访问地址 --- 字节低地址

         不管是程序还是CPU处理,都是以字节低地址为基本,这是真正理解字节序问题的基本标尺。

1.3.CPU寄存器与内存寄存器数据存放格式

         首先一定要认识到CPU寄存器的数据存放格式是统一的,以32位寄存器EAX为例说明,如图1.1所示。


图1.1 数据存储格式映射

         在CPU数据寄存器中,32位整型数据0x12345678换算为二进制后是按bit从左到右的顺序依次存放在数据寄存器EAX中,此时AX=0x5678,AH=0x56,AL=0x78。

         映射到内存时,数据存储格式因CPU体系架构平台的不同发生变化,出现了Big-endian和Little-endian之分,从总体上来分析,按照数据访问按照低字节地址的准则,假设此32位数据的内存地址为0xffffffff80000000,则:

l  Big-endian --- data(0xffffffff80000000) = 0x12,data(0xffffffff80000001) = 0x34

l  Litt-endian--- data(0xffffffff80000000) = 0x78,data(0xffffffff80000002) = 0x56

可见Big-endian将数据寄存器中最高8位的数据存放在内存低地址字节寄存器,Little-endian将数据寄存器中最低8位的数据存放在内存低地址字节寄存器中,所以评价标准是判断CPU将数据寄存器的最高8位还是最低8位存放在内存低地址寄存器中,按最高8位存放的即是Big,按最低8位存放的即是Little。

1.4.网络发送与接收的字节序问题 --- Big-endian

1.4.1.发送接收准则

         数据低地址顺序读取发送(发送端) ---〉数据低地址顺序接受存放(接受端)

1.4.2.乱序问题分析

图1.2 网络数据乱序问题

考虑一下情况的正确处理过程,以32位整型0x12345678为例:

Ø  主机发送端为little-endian

Ø  主机接受端为big-endian

 

主机端0x12345678内存字节流(数据访问低地址)为:78 --- 56 --- 34 --- 12,发送时转换为big-endian,字节流变为12 ---34 ---- 56 ---- 78,发送至接受端首先按big-endian存放即 12--- 34 --- 56 --- 78,开始接受端的转换,由于接受端也为big,转换后按低地址顺序为12 --- 34 --- 56 --- 78,这样接受端主机读取数据时仍然为0x12345678;如果发送端发送不做大小端转换,则接受端接受正常处理完毕得到的数据值为0x78563412。

经过上述分析,也可以看出大小端问题主要集中在多字节数据值问题上,而对字节流的处理是统一的。

 

[1:网卡发送时数据从主机内存寄存器拷贝至网卡内存数据寄存器,然后接受端接受到数据首先存放在网卡内存数据寄存器,然后拷贝至内存数据寄存器,都是按照大端处理,即顺序把内存之间或者网络间接收到的数据字节流,依次按照内存低地址准则存放,数据值按大端处理,这一步部分不需要人为程序干预,人为干预的主要是在发送时把主机内存中的数据转为大端字节流存储,这样网卡中断直接读取到网卡内存发送;接受时把主机内存中的接受到的数据,转化为主机字节序再处理]

[2:强制类型转换指针的数据内容即地址值不变]