大小端问题跟CPU的架构直接相关,我们常见的80x86系列CPU采用小端字节序模式。Windows平台就采用的80x86系列CPU,因此为小端字节序。
而主机之间进行网络通信时往往采用大端字节序,因此小端字节序机器在发送数据前需要进行字节序转换,在接收到数据处理处理数据之前要将网络字节序转换成本地字节序。
在Linux平台下提供了四个函数用来字节序转换:
1 2 3 4 5
| #include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);
|
Windows平台下也提供了相关的自己序转换函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| #include <WinSock2.h> unsigned __int64 __inline htond( double value );
unsigned __int32 __inline htonf( float value );
u_long WSAAPI htonl( _In_ u_long hostlong );
unsigned __int64 __inline htonll( unsigned __int64 value );
u_short WSAAPI htons( _In_ u_short hostshort );
double __inline ntohd( unsigned __int64 value );
float __inline ntohf( unsigned __int32 value );
u_long WSAAPI ntohl( _In_ u_long netlong );
u_long __inline ntohll( unsigned __int64 value );
u_short WSAAPI ntohs( _In_ u_short netshort );
|
这里有个技巧需要说明以下,比如要发送如下的结构体:
1 2 3 4 5
| struct foo { int a; long b; };
|
为了避免每个成员都调用字节序转换函数,可以在结构体的内部定义两个方法用于转换字节序,添加字节序后的foo如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| struct foo { int a; long b; void ntoh() { a = ntohl(a); b = ntohl(b); } void hton() { a = htonl(a); b = htonl(b); } };
|
需要特别注意的是,在发送结构体类型的数据时要注意字节对齐的问题,这里不再展开讨论,不同的平台有不同的解决办法。大体分为Winodws平台、AIX平台和GNU类平台。