Linux网络编程——字节序与网络字节序

说明
  本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
  QQ 群 号:513683159 【相互学习】
内容来源
  《Linux网络编程》
内容概述
  简单介绍字节序与网络字节序的概念
  两个示例:
    1.检查本机字节序
    2.字节序转换

字节序概念

  什么是字节序?
  字节序是由于不同主处理器(CPU)和操作系统(OS)对多字节的变量在内存中存放顺序的不同而产生的。
  字节序的分类?一般分为两类:
  ①小端字节序(Little Endian,LE):变量的内存地址起始地址存放低字节,高字节顺序存放
  ②大端字节序(Big Endian, BE):变量的内存地址起始地址存放高字节,低字节顺序存放
  实例Linux网络编程——字节序与网络字节序_第1张图片

示例:检查本机字节序

源代码:check_order.c

#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 字节序 变量类型

htonl()函数

  函数功能:将主机的无符号长整形数转换成网络字节顺序。

项目 说明
函数原型 extern uint32_t htonl (uint32_t __hostlong) __THROW __attribute__ ((__const__));
头文件 netinet/in.h
参数说明 __hostlong:主机字节顺序表达的32位数
返回值 返回一个网络字节顺序的值
注意

htons()函数

  函数功能:将主机的无符号短整形数转换成网络字节顺序。

项目 说明
函数原型 extern uint16_t htons (uint16_t __hostshort) __THROW __attribute__ ((__const__));
头文件 netinet/in.h
参数说明 __netshort:主机字节顺序表达的16位数
返回值 返回一个网络字节顺序的值。
注意

ntohl()函数

  函数功能:将一个32位数由网络字节顺序转换为主机字节顺序。

项目 说明
函数原型 extern uint32_t ntohl (uint32_t __netlong) __THROW __attribute__ ((__const__));
头文件 netinet/in.h
参数说明 __netlong:主机字节顺序表达的32位数
返回值 返回一个以主机字节顺序表达的数
注意

ntohs()函数

  函数功能:将一个无符号短整形数从网络字节顺序转换为主机字节顺序。

项目 说明
函数原型 extern uint16_t ntohs (uint16_t __netshort) __THROW __attribute__ ((__const__));
头文件 netinet/in.h
参数说明 __netshort:主机字节顺序表达的16位数
返回值 返回一个以主机字节顺序表达的数
注意

示例:字节序转换

源代码:turn_order.c

#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 

  值得注意的是:
    上面情形是在小端字节序系统上的结果,会发生改变。
    但是在大端字节序系统上,及时调用字节序转换函数也是不会发生改变的。

你可能感兴趣的:(嵌入式,书籍学习笔记,linux,网络,运维)