首先解释一下字节序的概念,所谓字节序是指多字节数据的存储顺序,比如0x1234要放在0000H和0001H两存储单元,有两种存储方式:大端格式为[0000H]=12,[0001H]=34和小端格式为[0000H]=34,[0001H]=12。
大端格式:将高位字节数据存储在低地址,低位字节数据存储在高地址
小端格式:将高位字节数据存储在高地址,低位字节数据存储在低地址
如何自身主机的字节序呢?看如下一个小demo你就明白了。可以自己在终端测试一下的,VC6.0也行的。
int main(int argc, char *argv[])
{
union{
short temp;
char test[sizeof(short)];
}un_tmp;
un_tmp.temp = 0x1234;
if ((un_tmp.test[0] == 0x12) && (un_tmp.test[1] == 0x34))
printf("大端格式:高位字节数据存储在低地址,低位字节数据存储在高地址");
if ((un_tmp.test[0] == 0x34) && (un_tmp.test[1] == 0x12))
printf("小端格式:高位字节数据存储在高地址,低位字节数据存储在低地址");
return 0;
}
我们知道在网络编程中会涉及到数据的发送接收问题,数据从一台计算机中发送到另一台计算机时有可能两台计算机的字节序不一致,从而导致数据传送错误,而且最关键的问题是你无法确定对方主机使用的字节序,这样,为了防止这种错误的出现,网络协议指定了通讯的字节序为大端格式,而本机对应的字节序不论大端格式还是小端格式都统称为主机序。
●只有在多字节数据处理时才需要考虑字节序,单字节数据根本不存在高低字节问题
●运行在同一台计算机上的进程相互通信时一般不用考虑字节序
●异构计算机之间的通讯,发送数据时需要转换自己的字节序为网络字节序(即统一转换为大端)
●异构计算机之间的通讯,接收数据时需要转换网络字节序为主机字节序
在需要字节序转换时,一般使用linux系统下arpa/inet.h头文件特定的转换函数。具体见如下:
1. 主机字节序 => 网络字节序
1.1 将32位主机字节序数据转换成网络字节序数据
uint32_t htonl(uint32_t hostint32);
1.2 将16位主机字节序数据转换成网络字节序数据
uint16_t htons(uint16_t hostint16);
例:
int main(int argc, char *argv[])
{
int a = 0x01020304;
short b = 0x0102;
printf("###:htonl(0x%08x)=0x%08x\n" ,a ,htonl(a));
printf("###:htons(0x%04x)=0x%04x\n" ,b ,htons(b));
return 0;
}
2. 网络字节序 => 主机字节序
2.1 将32位网络字节序数据转换成主机字节序数据
uint32_t ntohl(uint32_t netint32);
2.2 将16位网络字节序数据转换成主机字节序数据
uint16_t ntons(uint16_t netint16);
例:
int main(int argc, char *argv[])
{
int a = 0x01020304;
short b = 0x0102;
int net_int = htonl(a);
short net_short = htons(b);
printf("###:net_int = htonl(0x%08x) = 0x%08x\n" ,a ,net_int);
printf("###:net_short = htons(0x%04x) = 0x%04x\n" ,b ,net_short);
printf("###:ntohl(0x%08x)=0x%08x\n" ,net_int ,ntohl(net_int));
printf("###:ntohs(0x%04x)=0x%04x\n" ,net_short ,ntohs(net_short));
return 0;
}
3. 带自动转换字节序的地址转换函数
3.1 将点分十进制ip字符串strptr转换成对应的网络字节序的32位无符号整数addrptr。
int inet_pton(int family ,const char *strptr ,void *addrptr); //family是协议栈,一般填AF_INET
3.2 将主机字节序32位无符号整数addrptr转换成对应的点分十进制ip字符串strptr。
const char *inet_ntop(int family ,const void *addrptr ,char *strptr ,size_t len);
len的取值:
#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46
例:
int main(int argc, char *argv[])
{
int int_addr = 0;
char ip[16] = "192.168.1.1";
char new_ip[16] = "0.0.0.0";
printf("###:before inet_pton:int_addr = %d\n" ,int_addr);
inet_pton(AF_INET ,ip ,&int_addr);
printf("###:after inet_pton:int_addr = %d\n" ,int_addr);
printf("###:before inet_ntop:new_ip = %s\n" ,new_ip);
inet_ntop(AF_INET ,&int_addr ,new_ip ,INET_ADDRSTRLEN);
printf("###:after inet_ntop:new_ip = %s\n" ,new_ip);
return 0;
}
以上几个函数可以在linux终端下编写测试程序进行测试(VC6.0下不能测试,没有头文件),注意要包含对应头文件:#include
#include
#include