UN5L9——大小端模式
UN5L9——大小端模式
本章代码关键字
1 | BitConverter.IsLittleEndian //判断当前是否为小端模式 |
大小端模式
-
大端模式
是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中
这样的存储模式有点儿类似于把数据当作字符串顺序处理,地址由小向大增加,数据从高位往低位放
它更符合人类的阅读习惯 -
小端模式
是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中
何为高低字节:
我们阅读数字时,一般是从左往右看,看到数字的位的顺序就是从高到低,例如:127
127
的百位是高位,在左边,而个位是低位,在右边,我们阅读二进制的数0111 1111
也不例外,
因此,数字最左边的为就是高字节,最右边的位就是低字节
何为高低地址:内存开头一边的地址是低地址,末尾一边的地址是高地址
举例说明:十六进制数据:0x11223344
-
大端模式存储
从低地址向高地址看去(从内存首看到尾),数字的高位在头,数字的低位在尾,这样的顺序符合人类阅读习惯
1
2
3
4高字节 ——> 低字节
11 22 33 44
0 1 2 3
低地址 ——> 高地址 -
小端模式存储
从低地址向高地址看去(从内存首看到尾),数字的低位在头,数字的高位在尾,它的顺序与人类阅读习惯相反
1
2
3
4低字节 <—— 高字节
44 33 22 11
0 1 2 3
低地址 ——> 高地址
大小端模式会根据主机硬件环境不同、语言不同而有所区别,当我们前后端是不同语言开发且运行在不同主机上时
前后端需要对大小端字节序定下统一的规则
一般让前端迎合后端,因为字节序的转换也是会带来些许性能损耗的,网络游戏中要尽量减轻后端的负担, 一般情况下:
- C# 和 Java/Erlang/AS3 通讯需要进行大小端转换,前端C#从小变大
- C# 与 C++通信不需要特殊处理
我们不用死记硬背和谁通讯要注意大小端模式,当开发时,发现后端收到的消息和前端发的不一样
在协议统一的情况下,往往就是因为大小端造成的,这时我们再转换模式即可
注意:Protobuf已经帮助我们解决了大小端问题,即使前后端语言不统一,使用它也不用过多考虑字节序转换的问题
为什么有大小端模式
大小端模式其实是计算机硬件的两种存储数据的方式,我们也可以称大小端模式为 大小端字节序
对于我们来说,大端字节序阅读起来更加方便,为什么还要有小端字节序呢?
原因是,计算机电路先处理低位字节,效率比较高
计算机处理字节序的时候,不知道什么是高位字节,什么是低位字节
它只知道按顺序读取字节,先读第一个字节,再读第二个字节
如果是大端字节序,先读到的就是高位字节,后读到的就是低位字节,小端字节序正好相反
因为计算机都是从低位开始读取字节的,所以,计算机的内部处理都是小端字节序
但是,我们人类的读写习惯还是大端字节序
所以,除了计算机的内部处理,其它场合几乎都是大端字节序,比如网络传输和文件存储
一般情况下,操作系统都是小端模式,而通讯协议都是大端模式,但是具体的模式,还是要根据硬件平台,开发语言来决定
主机不同,开发语言不同,可能采用的大小端模式也会不一致
大小端模式对于我们的影响
我们记住一句话:只有读取的时候,才必须区分大小端字节序,其它情况都不用考虑
因此对于我们来说,在网络传输当中我们传输的是字节数组,那么我们在收到字节数组进行解析时,就需要考虑大小端的问题
虽然TCP/IP协议规定了在网络上必须采用网络字节顺序(大端模式),但是具体传输时采用哪种模式,都是根据前后端语言、设备决定的
在进行网络通讯时,前后端语言不同时,可能会造成大小端不统一,一般情况下:
- C# 和 Java/Erlang/AS3 通讯需要进行大小端转换,因为C#是小端模式 Java/Erlang/AS3是大端模式
- C# 与 C++通信不需要特殊处理 他们都是小端模式
大小端转换
-
判断是大小端哪种模式
取决于你的主机硬件环境、语言
1
print("是否是小端模式:" + BitConverter.IsLittleEndian);
-
简单的转换API 只支持几种类型
转换为网络字节序,相当于就是转为大端模式,以下的方法只支持
short
,int
,long
-
本机字节序转为网络字节序
它会输出字节顺序颠倒的
int
数(小端模式下),需要再自行转换为字节数组1
2int i = 99;
byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(i)); -
网络字节序转为本机字节序
1
2int receI = BitConverter.ToInt32(bytes, 0);
receI = IPAddress.NetworkToHostOrder(i);
-
-
通用的转换方式 —— 数组颠倒顺序
假设我们是小端模式,且远端是采用大端模式的,则从远端接收到的字节数组就需要转换,我们可以直接使用数组的倒转API即可
1
2
3
4
5
6int i = 99;
byte[] bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(i));
//假设我们是小端模式,且远端是采用大端模式的,则从远端接收到的字节数组就需要转换
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
print(BitConverter.ToInt32(bytes));