关于数据的封包发送和拆包使用

/* 前言:
 *    我们在使用buf数字传输数据的时候,通常会用来传输各种数据类型。
 * 一般的,我们会传输 char,short ,int ,float等,也包括各种 unsigned.
 *
 *
 * 一般的思路我们在发送的时候,会把数据一个个拆解成一个个byte,然后按顺序放到buf。
 * 在拿数据的时候,再一个一个的byte去拼接成具体数据,如下:
 * //包装数据
    buf[0]=Para.nv_list.sn>>24&0xff;
    buf[1]=Para.nv_list.sn>>16&0xff;
    buf[2]=Para.nv_list.sn>>8&0xff;
    buf[3]=Para.nv_list.sn;

    //拆解数据
    RX_info_s.sn=buf[0]<<24|buf[1]<<16|buf[2]<<8|buf[3];		//SN
 *
 *这样做思路非常的清晰,很直观,但是非常的累人,一个32的数据就得这样搞,如果有100个呢,你不得累死?
 * 之前的文章也有提到过读写flash的方式,用的是结构体+联合体映射方式跳过这一步,那个是应用到一个
 * nv参数列表的,适合大的buf包。想了解的可以去看看我之前的blog
 *
 * 疑问:
 *    那如果我一个buf都只有几个数据呢,比如有4个数据 char,short ,int ,float,
 * 如何快速的封包和拆包呢?下面我们一步步看看。
 *
 *
 *
 */

这次呢,我们来优化一下上次的方法。基本思想还是flash那篇文章,利用结构体和联合体

核心代码:

//编写一个内存copy函数
#define MCOPY(S,T,L)  do{int i=0;for(;i<L;i++)S[i]=T[i];}while(0)

//定义一个联合体来映射结构体
typedef union
{
    typedef struct
    {
        char  type; //协议类型
        short para_short;
        int   para_int;
        float para_float;

    }PACK_XX_S;  //XX代表包的名字,自定义

    char buf[sizeof (PACK_XX_S)]; //自动算struct大小,通用性变强
    PACK_XX_S nv_list;
}PACK_XX_U;

本次的修改,是把数据结构体放到了联合体里面,这样会显得代码更加的干净,而且结构体本身就只有联合体才可以访问。

模拟使用方法:(因为最近在学习QT,使用的QT环境)

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //一个发送数据包,一个接受数据包
    PACK_XX_U send_XX_pack;
    PACK_XX_U recv_XX_pack;

    //一个发送缓存包,一个接受缓存包
    //里面可能带头包头,检验等等
    char send_buf[13]={0};
    char recv_buf[13]={0};

    send_XX_pack.nv_list.type =1;
    send_XX_pack.nv_list.para_short =2;
    send_XX_pack.nv_list.para_int =3;
    send_XX_pack.nv_list.para_float =4.1234;
    printf("send\n");
    printf("type %d  ",send_XX_pack.nv_list.type);
    printf("type %d  ",send_XX_pack.nv_list.para_short);
    printf("type %d  ",send_XX_pack.nv_list.para_int);
    printf("type %f  \n",send_XX_pack.nv_list.para_float);
    
    //把数据拷贝到发送buf中,copy的位置根据自己协议定义
    MCOPY(send_buf,send_XX_pack.buf,12);

    //模拟收到数据
    MCOPY(recv_buf,send_buf,12);

    //把接收到的数据给数据包
    MCOPY(recv_XX_pack.buf,recv_buf,12);

    printf("recv\n");
    printf("type %d  ",recv_XX_pack.nv_list.type);
    printf("type %d  ",recv_XX_pack.nv_list.para_short);
    printf("type %d  ",recv_XX_pack.nv_list.para_int);
    printf("type %f  ",recv_XX_pack.nv_list.para_float);
    fflush(stdout);



    while(1);
    return a.exec();
}

运行结果:

可以看到 recv_XX_pack这个数据包,没有进行任何类型的值copy,只进行了内存copy,直接拿到了所有值,在封包的过程,也只有值和值的传递,不需要拆解byte。

以后如果需要增加协议包,只需要复制一份联合体,然后重新定义结构体中的数据即可。

例如你要发送一个3轴数据包,如下,修改点非常少,直接可以使用,这么干货,yyds给一个吧

//定义一个联合体来映射结构体
typedef union
{
    typedef struct
    {
        char  type; //协议类型
        float X;
        float Y;
        float Z;

    }PACK_XX_S;  //XX代表包的名字,自定义

    char buf[sizeof (PACK_XX_S)]; //为什么是12?,因为结构体内存对齐问题
    PACK_XX_S nv_list;
}PACK_ANGLE_U;

我们还可以继续优化联合体的内容,让它变得更加简洁。目前优化到最简洁的写法。如下

使用方法不变

typedef union
{
    struct PACK_XX_S
    {
        char  type; //protocol type
        short para_short;
        int   para_int;
        float para_float;

    }nv_list;  //XX is packet name

    char buf[sizeof (struct PACK_XX_S)];

}PACK_XX_U;

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值