说明:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
QQ 群 号:513683159 【相互学习】
内容来源:
《Linux网络编程》
内容概述:
简单介绍字节序与网络字节序的概念
两个示例:
1.检查本机字节序
2.字节序转换
什么是字节序?
字节序是由于不同主处理器(CPU)和操作系统(OS)对多字节的变量在内存中存放顺序的不同而产生的。
字节序的分类?一般分为两类:
①小端字节序(Little Endian,LE):变量的内存地址起始地址存放低字节,高字节顺序存放
②大端字节序(Big Endian, BE):变量的内存地址起始地址存放高字节,低字节顺序存放
实例:
#include
/**
* 字节序结构变量
* 联合类型的变量:所有成员占用同一段内存,修改一个成员会影响其他成员。
* 成员value高低端字节可由成员type按字节访问
*/
typedef union
{
unsigned short int value; //短整型变量
unsigned char byte[2]; //字符类型
}to;
int main(int argc,char *argv[])
{
/**
* 变量声明与赋值
* Note: value 和 byte成员共享同一块内存,
* 故可通过byte的不同成员访问value的高低字节
*/
to typeorder;
typeorder.value = 0xabcd;
/**
* 计算字节序结构中成员字节大小
*/
printf("Byte size:value = %ld,byte[0] = %ld\n",sizeof(typeorder.value),sizeof(typeorder.byte[0]));
/**
* 小端字节序检查
* 小端字节序(LE):起始地址存放低字节,高字节顺序存放
* Note:
* 低字节 = byte[1]: 0xab
* 高字节 = byte[0]: 0xcd
*/
if(typeorder.byte[0] == 0xcd && typeorder.byte[1] == 0xab)
{
printf("Low endian byte order byte[0]:0x%x,byte[1]:0x%x\n",
typeorder.byte[0],typeorder.byte[1]);
}
/**
* 大端字节序检查
* 大端字节序(BE):起始地址存放高字节,低字节顺序存放
* Note:
* 低字节 = byte[1]: 0xcd
* 高字节 = byte[0]: 0xab
*/
if(typeorder.byte[0] == 0xab && typeorder.byte[1] == 0xcd)
{
printf("High endian byte order byte[0]:0x%x,byte[1]:0x%x\n",
typeorder.byte[0],typeorder.byte[1]);
}
return 0;
}
编译:
执行指令:gcc check_order.c -o check_order
运行:
执行指令:./check_order
结果:
Byte size:value = 2,byte[0] = 1
Low endian byte order byte[0]:0xcd,byte[1]:0xab
很明显,我的系统是小端字节序。
网络字节序:多字节变量在网络传输时的表示方法,采用的是:高端字节序。
这是由于主机千差万别,故主机字节序不能做到统一,故对于网络传输的变量必须有一个统一的表示方法。
故为程序设计方便,让程序与平台无关,可在网络传输前先对字节序进行转换。
函数位置:netinet/in.h
主机和网络字节顺序之间转换的函数,如下:
htonl()
–“Host to Network Long” —— 主机字节序到网络字节序的长整型转换
htons()
–“Host to Network Short” ——主机字节序到网络字节序的短整型转换
ntohl()
–“Network to Host Long” —— 网络字节序到主机字节序的长整型转换
ntohs()
–“Network to Host Short” —— 网络字节序到主机字节序的短整型转换
可知,函数命名规则为:字节序 to 字节序 变量类型
函数功能:将主机的无符号长整形数转换成网络字节顺序。
项目 | 说明 |
---|---|
函数原型 | extern uint32_t htonl (uint32_t __hostlong) __THROW __attribute__ ((__const__)); |
头文件 | netinet/in.h |
参数说明 | __hostlong:主机字节顺序表达的32位数 |
返回值 | 返回一个网络字节顺序的值 |
注意 |
函数功能:将主机的无符号短整形数转换成网络字节顺序。
项目 | 说明 |
---|---|
函数原型 | extern uint16_t htons (uint16_t __hostshort) __THROW __attribute__ ((__const__)); |
头文件 | netinet/in.h |
参数说明 | __netshort:主机字节顺序表达的16位数 |
返回值 | 返回一个网络字节顺序的值。 |
注意 |
函数功能:将一个32位数由网络字节顺序转换为主机字节顺序。
项目 | 说明 |
---|---|
函数原型 | extern uint32_t ntohl (uint32_t __netlong) __THROW __attribute__ ((__const__)); |
头文件 | netinet/in.h |
参数说明 | __netlong:主机字节顺序表达的32位数 |
返回值 | 返回一个以主机字节顺序表达的数 |
注意 |
函数功能:将一个无符号短整形数从网络字节顺序转换为主机字节顺序。
项目 | 说明 |
---|---|
函数原型 | extern uint16_t ntohs (uint16_t __netshort) __THROW __attribute__ ((__const__)); |
头文件 | netinet/in.h |
参数说明 | __netshort:主机字节顺序表达的16位数 |
返回值 | 返回一个以主机字节顺序表达的数 |
注意 |
#include
#include
#define BITS16 16
#define BITS32 32
/**
* @union: 16位字节序结构变量
* 联合类型的变量:所有成员占用同一段内存,修改一个成员会影响其他成员。
* 成员value高低端字节可由成员type按字节访问
*/
typedef union
{
unsigned short int value; //16位短整型变量
unsigned char byte[2]; //字符类型
}to16;
/**
* @union: 32位字节序结构变量
* 联合类型的变量:所有成员占用同一段内存,修改一个成员会影响其他成员。
* 成员value高低端字节可由成员type按字节访问
*/
typedef union
{
unsigned int value; //32位整型变量
unsigned char byte[4]; //字符类型
}to32;
/**
* @function: 变量值打印函数
*
* @description:
* 从变量存储空间的第一个字节开始,按照字节打印
*
* @param begin: 变量的地址指针
* @param flag : 表示字长的标志变量
* BITS16 :打印16位变量的值
*/
void showvalue(unsigned char *begin, int flag)
{
int num = 0,i = 0;
if(flag == BITS16)
{
num = 2;
}
else if(flag == BITS32)
{
num = 4;
}
for(i = 0;i < num; i++)
{
printf("%x ",*(begin+i));
}
printf("\n");
}
int main(int argc,char *argv[])
{
/**
* 字节序变量定义
*/
to16 v16_orig, v16_turn1, v16_turn2;
to32 v32_orig, v32_turn1, v32_turn2;
/**
* 16位变量
*/
v16_orig.value = 0xabcd; //原始值赋值
v16_turn1.value = htons(v16_orig.value); //第一次转换的值
v16_turn2.value = htons(v16_turn1.value); //第二次转换的值
/**
* 32位变量
*/
v32_orig.value = 0x12345678; //原始值赋值
v32_turn1.value = htonl(v32_orig.value); //第一次转换的值
v32_turn2.value = htonl(v32_turn1.value); //第二次转换的值
/**
* 16位变量两次字节序转换结果输出:
*/
printf("16 host to network byte order change:\n");
printf("\t orig:\t");
showvalue(v16_orig.byte,BITS16); //16位数据的原始值
printf("\t 1 times:");
showvalue(v16_turn1.byte,BITS16); //16位数据的第一次转换后的值
printf("\t 2 times:");
showvalue(v16_turn2.byte,BITS16); //16位数据的第二次转换后的值
/**
* 32位变量两次字节序转换结果输出:
*/
printf("32 host to network byte order change:\n");
printf("\t orig:\t");
showvalue(v32_orig.byte,BITS32); //32位数据的原始值
printf("\t 1 times:");
showvalue(v32_turn1.byte,BITS32); //32位数据的第一次转换后的值
printf("\t 2 times:");
showvalue(v32_turn2.byte,BITS32); //32位数据的第二次转换后的值
return 0;
}
编译:
执行指令:gcc turn_order.c -o turn_order
运行:
执行指令: ./turn_order
结果:
16 host to network byte order change:
orig: cd ab
1 times:ab cd
2 times:cd ab
32 host to network byte order change:
orig: 78 56 34 12
1 times:12 34 56 78
2 times:78 56 34 12
值得注意的是:
上面情形是在小端字节序系统上的结果,会发生改变。
但是在大端字节序系统上,及时调用字节序转换函数也是不会发生改变的。