1、网络字节顺序和主机字节顺序的转换(htons ntohs htonl ntohl) 什么是网络字节顺序和主机字节顺序呢?在进行网络编程时,需要进行转换以统一“格式”简述:网络字节顺序 NBO(Network Byte Order): 按从高到低的顺序存储,在网络上使用统一的网络字节顺序,可以避免兼容性问题。 主机字节顺序(HBO,Host Byte Order): 不同的机器 HBO 不相同,与 CPU 设计有关详解:不同的 CPU 有不同的字节序类型 这些字节序是指整数在内存中保存的顺序 这个叫做主机序最常见的有两种1 Little endian:将低序字节存储在起始地址2 Big endi
2、an:将高序字节存储在起始地址LE little-endian 最符合人的思维的字节序地址低位存储值的低位地址高位存储值的高位怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说低位值小,就应该放在内存地址小的地方,也即内存地址低位反之,高位值就应该放在内存地址大的地方,也即内存地址高位BE big-endian最直观的字节序地址低位存储值的高位地址高位存储值的低位为什么说直观,不要考虑对应关系只需要把内存地址从左到右按照由低到高的顺序写出把值按照通常的高位到低位的顺序写出两者对照,一个字节一个字节的填充进去例子:在内存中双字 0x01020304(DWORD)的存储方式内存地址4000
3、4001 4002 4003LE 04 03 02 01BE 01 02 03 04例子:如果我们将 0x1234abcd 写入到以 0x0000 开始的内存中,则结果为big-endian little-endian0x0000 0x12 0xcd0x0001 0x23 0xab0x0002 0xab 0x340x0003 0xcd 0x12x86 系列 CPU 都是 little-endian 的字节序.网络字节顺序是 TCP/IP 中规定好的一种数据表示格式,它与具体的CPU 类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用 big endian
4、 排序方式。 为了进行转换 bsd socket 提供了转换的函数 有下面四个htons 把 unsigned short 类型从主机序转换到网络序htonl 把 unsigned long 类型从主机序转换到网络序ntohs 把 unsigned short 类型从网络序转换到主机序ntohl 把 unsigned long 类型从网络序转换到主机序在使用 little endian 的系统中 这些函数会把字节序进行转换在使用 big endian 类型的系统中 这些函数会定义成空宏同样 在网络程序开发时 或是跨平台开发时 也应该注意保证只用一种字节序 不然两方的解释不一样就会产生 bug.
5、函数例子解析之 htonl()简述:将主机的无符号长整形数转换成网络字节顺序。#include u_long PASCAL FAR htonl( u_long hostlong);hostlong:主机字节顺序表达的 32 位数。注释:本函数将一个 32 位数从主机字节顺序转换成网络字节顺序。返回值:htonl()返回一个网络字节顺序的值。inet_ntoa()简述:将网络地址转换成“.”点隔的字符串格式。#include char FAR* PASCAL FAR inet_ntoa( struct in_addr in);in:一个表示 Internet 主机地址的结构。注释:本函数将一个用
6、 in 参数所表示的 Internet 地址结构转换成以“.” 间隔的诸如 a.b.c.d”的字符串形式。请注意 inet_ntoa()返回的字符串存放在 WINDOWS 套接口实现所分配的内存中。应用程序不应假设该 内存是如何分配的。在同一个线程的下一个 WINDOWS 套接口调用前,数据将保证是有效。返回值:若无错误发生,inet_ntoa()返回一个字符指针。否则的话,返回NVLL。其中的数据应在下一个 WINDOWS 套接口调用前复制出来。网 络中传输的数据有的和本地字节存储顺序一致,而有的则截然不同,为了数据的一致性,就要把本地的数据转换成网络上使用的格式,然后发送出去,接收的时候也
7、 是一样的,经过转换然后才去使用这些数据,基本的库函数中提供了这样的可以进行字节转换的函数,如和 htons( ) htonl( ) ntohs( ) ntohl( ),这里 n 表示 network,h 表示host,htons( ) htonl( )用于本地字节向网络字节转换的场合,s 表示short,即对 2 字节操作,l 表示 long 即对 4 字节操作。同样 ntohs( )ntohl( )用于网络字节向本地格式转换的场合。附注:一、字节序定义字节序,顾名思义字节的顺序,再多说两句就是大于一个字节类型的数据在内存中的存放顺序(一个字节的数据当然就无需谈顺序的问题了)。其实大部分人在
8、实际的开发中都很少会直接和字节序打交道。唯有在跨平台以及网络程序中字节序才是一个应该被考虑的问题。在所有的介绍字节序的文章中都会提到字节序分为两类:Big-Endian 和Little-Endian。引用标准的 Big-Endian 和 Little-Endian 的定义如下:a) Little-Endian 就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。b) Big-Endian 就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。c) 网络字节序:4 个字节的 32 bit 值以下面的次序传输:首先是07bit,其次 815bit,然后 1623bit,最后是
9、 2431bit。这种传输次序称作大端字节序。由于 TCP/IP 首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。比如,以太网头部中 2 字节的“以太网帧类型”,表示后面数据的类型。对于 ARP 请求或应答的以太网帧类型来说,在网络传输时,发送的顺序是0x08,0x06。在内存中的映象如下图所示:栈底 (高地址)-0x06 - 低位 0x08 - 高位-栈顶 (低地址)该字段的值为 0x0806。按照大端方式存放在内存中。二、高/低地址与高低字节首先我们要知道我们 C 程序映像中内存的空间布局情况:在C 专家编程中或者Unix 环境高级编程中有关于内存空间布局情况
10、的说明,大致如下图:- 最高内存地址 0xffffffff| 栈底. 栈.栈顶-|/|/NULL (空洞)/|/|-堆-未初始化的数据-(统称数据段)初始化的数据-正文段(代码段)- 最低内存地址 0x00000000以上图为例如果我们在栈上分配一个 unsigned char buf4,那么这个数组变量在栈上是如何布局的呢注 1?看下图:栈底 (高地址)-buf3buf2buf1buf0-栈顶 (低地址)现在我们弄清了高低地址,接着来弄清高/低字节,如果我们有一个 32位无符号整型 0x12345678(呵呵,恰好是把上面的那 4 个字节 buf 看成一个整型),那么高位是什么,低位又是什么
11、呢?其实很简单。在十进制中我们都说靠左边的是高位,靠右边的是低位,在其他进制也是如此。就拿 0x12345678 来说,从高位到低位的字节依次是 0x12、0x34、0x56和 0x78。高低地址和高低字节都弄清了。我们再来回顾一下 Big-Endian 和Little-Endian 的定义,并用图示说明两种字节序:以 unsigned int value = 0x12345678 为例,分别看看在两种字节序下其存储情况,我们可以用 unsigned char buf4来表示 value:Big-Endian: 低地址存放高位,如下图:栈底 (高地址)-buf3 (0x78) - 低位buf2
12、 (0x56)buf1 (0x34)buf0 (0x12) - 高位-栈顶 (低地址)Little-Endian: 低地址存放低位,如下图:栈底 (高地址)-buf3 (0x12) - 高位buf2 (0x34)buf1 (0x56)buf0 (0x78) - 低位-栈顶 (低地址)在现有的平台上 Intel 的 X86 采用的是 Little-Endian,而像 Sun 的SPARC 采用的就是 Big-Endian。三、例子嵌入式系统开发者应该对 Little-endian 和 Big-endian 模式非常了解。采用 Little-endian 模式的 CPU 对操作数的存放方式是从低字
13、节到高字节,而 Big-endian 模式对操作数的存放方式是从高字节到低字节。例如,16bit 宽的数 0x1234 在 Little-endian 模式 CPU 内存中的存放方式(假设从地址 0x4000 开始存放)为:内存地址 存放内容0x4001 0x120x4000 0x34而在 Big-endian 模式 CPU 内存中的存放方式则为:内存地址 存放内容0x4001 0x340x4000 0x1232bit 宽的数 0x12345678 在 Little-endian 模式 CPU 内存中的存放方式(假设从地址 0x4000 开始存放)为:内存地址 存放内容0x4003 0x120
14、x4002 0x340x4001 0x560x4000 0x78而在 Big-endian 模式 CPU 内存中的存放方式则为:内存地址 存放内容0x4003 0x780x4002 0x560x4001 0x340x4000 0x12四。不同的 CPU 上运行不同的操作系统,字节序也是不同的,参见下表。处理器 操作系统 字节排序Alpha 全部 Little endianHP-PA NT Little endianHP-PA UNIX Big endianIntelx86 全部 Little endian -x86 系统是小端字节序系统Motorola680x() 全部 Big endianMIPS NT Little endianMIPS UNIX Big endianPowerPC NT Little endianPowerPC 非 NT Big endian -PPC 系统是大端字节序系统RS/6000 UNIX Big endianSPARC UNIX Big endianIXP1200 ARM 核心 全部 Little endian