字节序
字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
主机字节序
主机字节序就是我们平常说的大端和小端模式:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。引用标准的Big-Endian和Little-Endian(大小端)的定义如下:
小端模式
a) Little-Endian(小端模式)就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。如0x04030201这个数据按小段模式存放在2000——2003这一段地址中存放的顺序是:
2003 存放 0000 0100 (0x04)
2002 存放 0000 0011 (0x03)
2001 存放 0000 0010 (0x02)
2000 存放 0000 0001 (0x01)
大端模式
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。如0x04030201这个数据按大段模式存放在2000——2003这一段地址中存放的顺序是:
2003 存放 0000 0001 (0x01)
2002 存放 0000 0010 (0x02)
2001 存放 0000 0011 (0x03)
2000 存放 0000 0100 (0x04)
网络字节序
网络字节序:4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序,一个字节的数据没有顺序的问题了。
所以:在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。由于这个问题曾引发过血案!公司项目代码中由于存在这个问题,导致了很多莫名其妙的问题,所以请谨记对主机字节序不要做任何假定,务必将其转化为网络字节序再赋给socket。
字节序转换函数:
大小端转换函数
即主机字节序和网络字节序间的转换函数:
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
h表示host,指小端,n表示network指大端,l表示32位长整数,s表示16位短整数。
注意:32位是用来转换IP地址的,16位是用来转换端口号的
实现方式:
#include <stdio.h>
#include <stdlib.h>
typedef unsigned short int uint16;
typedef unsigned long int uint32;
// 短整型大小端互换
#define BigLittleSwap16(A) ((((uint16)(A) & 0xff00) >> 8) |(((uint16)(A) & 0x00ff) << 8))
// 长整型大小端互换
#define BigLittleSwap32(A) ((((uint32)(A) & 0xff000000) >> 24) |(((uint32)(A) & 0x00ff0000) >> 8)
|(((uint32)(A) & 0x0000ff00) << 8) |(((uint32)(A) & 0x000000ff) << 24))
// 本机大端返回1,小端返回0
int checkCPUendian()
{
union{
unsigned long int i;
unsigned char s[4];
}c;
c.i = 0x12345678;
return (0x12 == c.s[0]);
}
// 模拟htonl函数,本机字节序转网络字节序
unsigned long int HtoNl(unsigned long int h)
{
// 若本机为大端,与网络字节序同,直接返回
// 若本机为小端,转换成大端再返回
return checkCPUendian() ? h : BigLittleSwap32(h);
}
// 模拟ntohl函数,网络字节序转本机字节序
unsigned long int NtoHl(unsigned long int n)
{
// 若本机为大端,与网络字节序同,直接返回
// 若本机为小端,网络数据转换成小端再返回
return checkCPUendian() ? n : BigLittleSwap32(n);
}
// 模拟htons函数,本机字节序转网络字节序
unsigned short int HtoNs(unsigned short int h)
{
// 若本机为大端,与网络字节序同,直接返回
// 若本机为小端,转换成大端再返回
return checkCPUendian() ? h : BigLittleSwap16(h);
}
// 模拟ntohs函数,网络字节序转本机字节序
unsigned short int NtoHs(unsigned short int n)
{
// 若本机为大端,与网络字节序同,直接返回
// 若本机为小端,网络数据转换成小端再返回
return checkCPUendian() ? n : BigLittleSwap16(n);
}
int main()
{
unsigned long int a = 0x01020304;
a = HtoNl(a);
printf("%08x",a);
system("pause");
return 0;
}
字符串转换网络字节序的函数:
把字符串形式的"192.168.1.123"转为网络能识别的格式:
int inet_aton(const char *strptr,struct in_addr *addrptr);
/*若字符串有效返回1,否则返回0*/
把网络格式的ip地址转为字符串形式:
Char * inet ntoa(struct inaddr inaddr);
/*返回指向一个点分十进制数串的指针*/