一、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文库