【网络编程系列】一:字节顺序的大端与小端表示法

时间:2022-05-04
本文章向大家介绍【网络编程系列】一:字节顺序的大端与小端表示法,主要内容包括一、字节序、二、大端与小端、三、为什么要注意字节序、四、判断机器的字节序、五、网络序和主机序、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

一、字节序

字节序,也就是字节的顺序,指的是多字节的数据在内存中的存放顺序。

在几乎所有的机器上,多字节对象都被存储为连续的字节序列。例如:如果C/C++中的一个int型变量 a 的起始地址是&a = 0x100,那么 a 的四个字节将被存储在存储器的0x1000x101,0x1020x103位置。

根据整数 a 在连续的 4 byte 内存中的存储顺序,字节序被分为大端序(Big Endian) 与 小端序(Little Endian)两类。 然后就牵涉出两大CPU派系:

  • Motorola 6800,PowerPC 970,SPARC(除V9外)等处理器采用 Big Endian方式存储数据;
  • x86系列,VAX,PDP-11等处理器采用Little Endian方式存储数据。

另外,还有一些处理器像ARM, DEC Alpha的字节序是可配置的。

二、大端与小端

那么,到底什么是大端,什么是小端? 如下图:

我相信上面的图已经够直观了。也就是说:

  • Big Endian 是指低地址端 存放 高位字节。
  • Little Endian 是指低地址端 存放 低位字节。

各自的优势:

  1. Big Endian:符号位的判定固定为第一个字节,容易判断正负。
  2. Little Endian:长度为1,2,4字节的数,排列方式都是一样的,数据类型转换非常方便。

三、为什么要注意字节序

如果你写的程序只在单机环境下面运行,并且不和别人的程序打交道,那么你完全可以忽略字节序的存在。

但是,如果你的程序要跟别人的程序产生交互呢? 比如,当一个 C/C++ 的程序要与一个 Java 程序交互时:

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

试想,如果你的C/C++程序将变量 a = 0x12345678 的首地址传递给了Java程序,由于Java采取 Big Endian 方式存储数据,很自然的它会将你的数据翻译为 0x78563412。显然,问题就出现了!!!

另外,网络传输一般采用 Big Endian,也被称之为网络字节序,或网络序。当两台采用不同字节序的主机通信时,在发送数据之前都必须经过字节序的转换成为网络字节序后再进行传输。

四、判断机器的字节序

由于 C/C++ 存储数据时的字节序依赖所在平台的CPU,所以我们可以通过C/C++程序判定机器的端序:

void Endianness()
{
	int a = 0x12345678;
	if( *((char*)&a) == 0x12)
		cout << "Big Endian" << endl;
	else
		cout << "Little Endian" << endl;
}

五、网络序和主机序

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

主机字节序:整数在内存中存储的顺序,现在 Little Endian 比较普遍。(不同的 CPU 有不同的字节序)

在进行网络通信时 通常需要调用相应的函数进行主机序和网络序的转换。Berkeley socket API 定义了一组转换函数,用于16和32bit整数在网络序和本机字节序之间的转换。htonl,htons用于本机序转换到网络序;ntohl,ntohs用于网络序转换到本机序

在Linux和Windows网络编程时需要用到htons和htonl函数,用来将主机字节顺序转换为网络字节顺序。

     在Intel机器下,执行以下程序

int main()
{
   printf("%d /n",htons(16));
      return 0;
}

得到的结果是4096,初一看感觉很怪。

    解释如下,数字16的16进制表示为0x0010,数字4096的16进制表示为0x1000。 由于Intel机器是小尾端,存储数字16时实际顺序为1000,存储4096时实际顺序为0010。因此在发送网络包时为了报文中数据为0010,需要经过htons进行字节转换。如果用IBM等大尾端机器,则没有这种字节顺序转换,但为了程序的可移植性,也最好用这个函数。

   另外用注意,数字所占位数小于或等于一个字节(8 bits)时,不要用htons转换。这是因为对于主机来说,大小尾端的最小单位为字节(byte)。