Dotcpp  >  编程教程  >  TCP协议客户端及代码实现  >  什么是字节序?大小端还有网络序和主机序?

什么是字节序?大小端还有网络序和主机序?

点击打开在线编译器,边学边练

1.字节序

字节序,又称端序或尾序,指的是多字节数据在内存中的存放顺序。学过C语言后,我们知道一个int型变量a是占用4个字节,假设它的起始地址也就是&a是0x10处,那么变量a的四个字节将会被存储在0x10、0x11、0x12和0x13这四个字节位置上。


但是当我们写好通信程序发送数据时候的时候,这个a变量通过TCP连接传输后收到的与发送的不一致,即有可能发过去的序列变成了0x12、0x13的值在前,0x10、0x11上的值在后,这样组成的四个字节的int类型值肯定就不一样了。

所以要引入大端和小端的概念。


2.大端和小端

计算机有两种储存数据的方式:大端字节序(Big Endian)和小端字节序(Little Endian)。


大端模式:是指数据的高字节保存在内存的低地址中,低字节保存在内存的高地址端。

小端模式:是指数据的高字节保存在内存的高地址中,低字节保存在内存的低地址端。


以一个两字节short型变量0x0102的存储举例:

大端字节序:高位字节在前,低位字节在后,01|02,从左往右看着更习惯。

小端字节序:低位字节在前,高位字节在后,02|01,也存在这种存储顺序。


我们以0x12345678这个数字为例,它的大端模式和小端模式分别如下:

大小端存储顺序

3.原因?

计算机处理字节序的时候,不知道什么是高位字节,什么是低位字节。它只知道按顺序读取字节,先读第一个字节,再读第二个字节…

如果是大端字节序,先读到的就是高位字节,后读到的就是低位字节;小端字节序正好相反。

如果这样,那统一用符合我们人类读写习惯的大端序就好了呀,为何还要弄出个小端序了?

这是疑问计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的,所以计算机的内部处理都是小端字节序。

但是人类还是习惯读写大端字节序,所以除了计算机的内部处理,其他的场合几乎都是大端字节序,比如网络传输和文件储存。

4.网络序和主机序

明白了大小端之后,网络序和主机序也就好理解了,

网络字节序:TCP/IP各层协议将字节序定义为Big Endian,即大端模式,TCP/IP协议中使用的字节序是大端序。

主机字节序:整数在内存中存储的顺序,目前以Little Endian,即小端模式,比较普遍(不同的CPU有不同的字节序)。


C/C++语言编写的程序里数据存储顺序是跟编译平台所在的CPU相关的,而现在比较普遍的x86处理器是小端模式(Little Endian)。Java编写的程序则唯一采用Big Endian方式来存储数据。

所以,如果你的C/C++程序通过Socket将变量a = 0x12345678的首地址传递给了Java程序,由于Java采取Big Endian方式存取数据,很显然,本地数据没问题,传过去就变成0x78563412,这就出问题了。毕竟不是所有的客户端和服务端都是同一种语言、同一种CPU。因此转换的问题就来了


5.如何转换

为避免开头说到的网络通信中存在的问题,我们可以在传输数据之前和接收数据之后对数据进行相应处理,也就是主机序和网络序的转换。


C/C++提供了相应的函数接口,htons、htonl用于主机序转换到网络序ntohl、ntohs用于网络序转换到主机序

其中h表示host主机,n表示network网络。有兴趣可以点击阅读



本文固定URL:https://www.dotcpp.com/course/816

Dotcpp在线编译      (登录可减少运行等待时间)