flatbuffers(c++)的深入理解和使用案例(二)

一、flatbuffers数据类型

1.标量类型

即基本类型,如int,float,bool等。标量类型使用直接寻址进行数据访问。

2.struct类型

除了基本类型之外,flatBuffers中只有 struct类型使用直接寻址进行数据访问。

flatBuffers规定struct类型用于存储那些约定成俗、永不改变的数据,这种类型的数据结构一旦确定便永远不会改变,struct所有字段都是必填的,因而没有默认值,字段可能不会被添加或被弃用,所以 structs不提供前向/后向兼容性。在这个规定之下,为了提高数据访问速度,flatBuffers单独对struct使用了直接寻址的方式。字段的顺序即为存储的顺序。

struct有的特性一般不作为schema文件的根。

3.vector类型

vector 类型实际上就是 schema中声明的数组类型,flatBuffers中也没有单独的类型和它对应,但是它却有自己独立的一套存储结构,在序列化数据时先会从高位到低位依次存储 vector内部的数据,然后再在数据序列化完毕后写入vector的成员个数。

4.string类型

flatBuffers 字符串按照 utf-8 的方式进行了编码,在实现字符串写入的时候将字符串的编码数组当做了一维的vector来实现。string本质上也可以看做是byte的vector,因此创建过程和vector基本一致,唯一的区别就是字符串是以null结尾,即最后一位是 0。

5.union类型

union类型比较特殊,fatBuffers规定这个类型在使用上具有如下两个限制:

union类型的成员只能是table类型。

union类型不能是一个schema文件的根。

flatBuffers 中没有特定类型表示union,而是会生成一个单独的类对应 union 的成员类型。与其他类型的主要区别是需要先指定类型,在序列化union的时候一般先写入union的type,然后再写入union的数据偏移;在反序列化union的时候一般先解析出union的type,然后再按照type对应的table类型来解析union对应的数据。

6.enum类型

flatBuffers中的enum类型在数据存储的时候是和byte类型存储的方式一样的。因为和union类型相似,enum类型在flatBuffers中也没有单独的类与它对应,在schema中声明为enum的类会被编译生成单独的类。

enum类型不能是一个schema文件的根。

7.table类型

table是在flatBuffers中定义对象的次要形式,由一个名称和一个字段列表组成。能够蕴含下面定义的所有类型。每个字段包含名称、类型和默认值三局部;每个字段都有默认值,如果没有明确写出则默认为 0 或者 null。每个字段都不是必须的,能够为每个对象抉择要省略的字段,这是flatBuffers向前和向后兼容的机制。

8.namespace

namespace定义命名空间,能够定义嵌套的命名空间,用 . 宰割。

9.root_type Monster

用于指定序列化后的数据的 root table。必须有根类型使用root_type标明根类型。

二、flatbuffers的使用方法及步骤

1.首先定义协议文件,即Schema文件,后缀名为.fbs。

2.利用安装好的flatc应用程序将Schema文件转换为c++所需要的XXX_generated.h头文件。安装教程和转换命令见flatbuffers的简介、下载安装和使用教程(一)_做一个坚强的女汉子的博客-CSDN博客

3.将XXX_generated.h头文件和flatbuffers源码中的头文件放到工程文件目录下。

4.使用时加入#include "XXX_generated.h"即可对其进行使用。

三、flatbuffers的使用案例

此处的使用案例是结合qt中websocket通信使用的,通过二进制的方式在服务端和客户端之间进行数据的传递。

界面:

 

 Schema文件内容如下:

namespace Zoo;

enum Animal_Type:byte
{
     tiger = 0,//老虎
     lion=1,//狮子
     giraffe=2,//长颈鹿
     kangaroo=3,//袋鼠
     monkey=4,//猴
}

table Animal_Fb
{
     type:Animal_Type;
     note:string;
     num:long;
}

table Director_Fb
{
     name:string;
     age:long;
}

table Zoo_Fb
{
     name:string;
     director:Director_Fb;
     animals:[Animal_Fb];
}

root_type Zoo_Fb;

序列化过程:

flatbuffers::FlatBufferBuilder builder;

    auto director = Zoo::CreateDirector_Fb(builder,builder.CreateString("张三"),20);

    std::vector<flatbuffers::Offset<Zoo::Animal_Fb>> vecAnimal;
    auto animal1 = Zoo::CreateAnimal_Fb(builder,Zoo::Animal_Type::Animal_Type_tiger,builder.CreateString("老虎"),10);
    auto animal2 = Zoo::CreateAnimal_Fb(builder,Zoo::Animal_Type::Animal_Type_lion,builder.CreateString("狮子"),8);
    auto animal3 = Zoo::CreateAnimal_Fb(builder,Zoo::Animal_Type::Animal_Type_giraffe,builder.CreateString("长颈鹿"),15);
    auto animal4 = Zoo::CreateAnimal_Fb(builder,Zoo::Animal_Type::Animal_Type_kangaroo,builder.CreateString("袋鼠"),88);
    auto animal5 = Zoo::CreateAnimal_Fb(builder,Zoo::Animal_Type::Animal_Type_monkey,builder.CreateString("猴子"),469);
    vecAnimal.push_back(animal1);
    vecAnimal.push_back(animal2);
    vecAnimal.push_back(animal3);
    vecAnimal.push_back(animal4);
    vecAnimal.push_back(animal5);
    auto animals = builder.CreateVector(vecAnimal);

    auto zoo = Zoo::CreateZoo_Fb(builder,builder.CreateString("小小动物园"),director,animals);
    builder.Finish(zoo);


    char buffer[1024] = {0};
    memcpy(buffer, builder.GetBufferPointer(), builder.GetSize());

    QByteArray array(buffer,builder.GetSize());

 反序列化过程:

//    flatbuffers::FlatBufferBuilder builder;
//    builder.PushBytes((const uint8_t*)message.data(), message.size());
//    auto zoo = Zoo::GetZoo_Fb(builder.GetCurrentBufferPointer());
    auto zoo = Zoo::GetZoo_Fb(message);

    std::string zooName = zoo->name()->str();
    ui->m_pTextReceive->append("动物园名称为:"+QString::fromStdString(zooName));
    auto director = zoo->director();
    ui->m_pTextReceive->append("管理员名称为:"+QString::fromStdString(director->name()->str())+","
                               + "管理员年龄为:"+QString::number(director->age()));
    auto animals = zoo->animals();
    for(int i = 0;i<(int)animals->Length();i++)
    {
        auto type = animals->Get(i)->type();
        std::string note = animals->Get(i)->note()->str();
        long num = animals->Get(i)->num();
        ui->m_pTextReceive->append("动物类型为:"+QString::fromStdString(Zoo::EnumNamesAnimal_Type()[type])+","
                                   + "备注为:"+QString::fromStdString(note)+","
                                   + "数量为:"+QString::number(num));
    }

查看.h文件,看到可以通过EnumNames枚举名称()函数来获取相应的枚举类型的字符串形式,写法如下

Zoo::EnumNamesAnimal_Type()[type])  type为枚举值

完整代码见flatbuffers在QWebSocket通信中序列化和反序列化的使用案例(c++)-C++文档类资源-CSDN文库 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值