字节序
概念:
是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。在计算机中是以字节为单位,每个地址对应一个字节,一个字节8bit。在C中,除了8bit的char以外,还有16bit的short,32位的int,64位long,当然具体要由编译器决定,可以通过sizeof来获取不同类型在内存中占用的字节数。在计算机系统中,当物理单位的长度大于1个字节时(所以char数据就不用区分字节序),就要区分字节顺序。常见的字节顺序有两种:大端和小端,当然还有其他字节顺序,但不常见,例如Middle Endian,通俗的讲,字节序就是cpu对内存中进行存储的顺序(以字节为单位进行存取)
常见分类:
内存地址有高低之分,数据二进制有高低之分,数据在内存中进行存储,到底是从低地址开始还是从高地址开始?通常情况下我们将字节序分为大端字节序和小端字节。
大端字节序:低地址存储高位数据,高地址存储低位数据
小端字节序:低地址存储低位数据,高地址存储高位地址
举例:现在有一个int a = 0x01020304
使用大端存储:01 02 03 04
使用小端存储:04 03 02 01
字节序所针对的数据类型:储存单元大于1字节的数据类型——short,long,int,float,double等等(单字节储存的数据四不存在字节比如:char类型)\
为啥要有大小端之分呢?直接统一不行吗?
原来,计算机在处理数据的时候,先处理低位字节的数据,所以计算机内部基本都是小端字节序,而我们人在思考的时候一般使用的是大端的方式,所以就有了大小端之分。
网络字节序
先来思考一个问题,主机字节序不同对于网络通信的影响:
如果网络通信的两台主机,主机字节序相同,则可以不考虑字节问题,但是如果不同,就有可能造成数据二义;(在解释的时候大端主机和小端主机会对数据解释不同)
注意:数据的传输一定是发送了什么数据,对方就接收了什么数据;
解决方案:网络传输的数据,使用统一的字节序标准——网络字节序(采用的是大端字节序),如果你是大端,不管你是什么字节序的主机,不需要关心对方主机的字节序了,因为对方发送到网络中的数据都是网络字节序,你只需要更具自己的主机字节序进行转换即可。
注意:如果编写网络程序,要考虑跨平台问题,存储单元超过一个字节,就要使用网络字节序进行通信。
这时候我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?
1.发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
2.TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;
为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。
1.这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回; 如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。
2.网络字节序和主机字节序大小端一般是由CPU架构决定的。
网络字节序和主机字节序的区别
1.网络字节序(Network Order):TCP/IP各层协议将字节序定义为Big Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
2.主机字节序(Host Order):整数在内存中保存的顺序,它遵循Little Endian规则(不一定,要看主机的CPU架构)。所以当两台主机之间要通过TCP/IP协议进行通信的时候就需要调用相应的函数进行主机序列(Little Endian)和网络序(Big Endian)的转换,否则就会造成数据的二义性。