littleEndian bigEndian - yaokun123/php-wiki GitHub Wiki

主机字节序和网络字节序

一、简介

在使用网络进行程序设计中会碰到的一个问题是字节序的问题,在基于单机或者同类型机器进行开发的过程中很少遇到。由于网络的他点是将Internet上不同的网络设备和主机进行连接和通信,这决定了使用网络进行开发的程序的特点就是要兼容各种类型的设备,其中的数据在不同的设备上要有唯一的含义。字节序的问题是上述情况下的典型问题。

二、字节序的含义

字节序的问题是由于CPU对整数在内存中的存放方式造成的。多于一个字节的数据类型在内存中的存放顺序叫主机字节序。最常见的字节序有两种,小端字节序和大端字节序。

小端字节序Little Endian(LE)

将数据的最低字节放在内存的起始位置。
小端字节序的特点是:内存地址较低的位存放数据的低位,内存地址高的位存放数据的高位,与习惯思维一致。
采用低字节序的CPU有x86架构的Intel系列产品。

大端字节序Big Endian(BE)

将数据的高字节存放在内存的起始位置。
大端字节序的特点是:内存中低字节位置存放数据的高位字节,内存中的高位字节存放数据的较低字节数据,与思维习惯不一致。
但是与实际数据的表达方式是一致的。
如果将内存中的数据直接放在文件中,打开文件查看会发现和原来的数据的高低位一致。
采用大端字节序的典型代表有PowerPC的UNIX系统。

例如,对于一个8位字节的数据0x12345678,假设在内存中存放的开始地址为0x1000,则在小端字节序和大端字节序系统中的方式如下:

内存地址 0x1000 0x1001 0x1002 0x1003
小端字节序 0x78 0x56 0x34 0x12
大端字节序 0x12 0x34 0x56 0x78

而如果将0x12345678写入内存地址0x1000开始的地方,在内存中的值为如下:

内存地址 小端字节序 大端字节序
0x1000 0x12 0x78
0x1001 0x34 0x56
0x1002 0x56 0x34
0x1003 0x78 0x12

系统对多字节数据的不同存放方法造成了使用方法的问题,例如,在x86系统主机A上的一个值为0x12345678,数据通过网络传送到PowerPC上的一个运行UNIX的主机B上,在B上此值解释为0x78563412,与原来的数据不同,这样就造成了传输上兼容性方面的困难。

三、网络字节序的转换

网络的字节序标准规定为大端字节序,不同平台上会对主机字节序进行转化后再进行传送,到主机后再转化为主机字节序,数据的传输就不会产生问题。同一个数据在不同平台上可以使用网络字节序的转换函数来实现。

如图5.31所示为主机A中的应用程序将变了a中的值0x12345678,通过网络传递给主机B中的应用程序中的变量b,如果不进行网络字节序转换,b的值为0x78563412

如图5.32所示,如果进行网络字节序转换,a的值与b的值均为0x12345678。 进行网络字节序转换的函数有htons()、ntohs()、htonl()、ntohl()等,其中s是short数据类型的意思,l是long数据类型的意思,h是host即主机的意思,n是network即网络的意思。

htons():表示对于short类型的变量,从主机字节许转换为网络字节序。
ntohs():表示对于short类型的变量,从网络字节序转换为主机字节序。
htonl():表示对于long类型的变量,从主机字节许转换为网络字节序。
ntohl():表示对于long类型的变量,从网络字节序转换为主机字节序。

字节序的转换函数并没有转换符号类型变量,是否为符号类型是由应用程式来确定的,与字节无关。