- 摘要
Google Protocol Buffer 是一个优秀的基于二进制的网络消息编解码框架。应用于项目时,可以节省不少的人力资源、开发时间和程序BUG。但其不足之处是protobuf编译器生成的C++消息类(或者Java等其他语言的消息类)冗余数据过多,需要依赖于protobuf的编解码库,一般情况下都不能用于作为业务逻辑对象。因此大部分情况下,程序都需要另外独立定义业务逻辑对象,并且使用protobuf定义相应(不一定100%相同)的消息,并手写代码,在protobuf消息对象和C++/Java业务对象之间进行转换。
protobuf消息还有另外一个缺点,是数据类型不够丰富,特别是指针,map集合不支持,你支持继承。通过required、optional属性的扩展可以让其支持指针,通过多字段,也可以让其支持map集合。
因在工程中,有太多的,太过于相似的转换代码,因此才有想法写一个C++类与google protobuf消息直接进行转换的工具。当然一次为蓝本,还可以转换为Java、C#等其他语言。当然转换后的代码不可能100%的可以直接工作,但是可以肯定的是已经完成了99%的工作,就剩下1%一点点的手动修改即可。
关于继承的映射。基类消息作为子类消息的第一个字段,明白字段名称为base;
- 数据类型映射规则
编号 |
C++数据类型 |
限制 |
protobuf数据类型 |
备注 |
1 |
bool |
required |
bool |
|
2 |
(unsigned) char |
required |
uint32 or int32 |
protobuf 不支持char类型,建议使用int替代 |
3 |
(unsigned) short |
required |
uint32 or int32 |
protobuf 不支持short类型,建议使用int替代 |
4 |
(unsigned) int |
required |
sfixed32 or fixed32 |
|
5 |
(unsigned) long |
required |
sfixed32 or fixed32 |
建议使用 int替代 |
6 |
std::string |
required |
bytes |
bytes可以更好的支持中文,protobuf string只支持asscii 不要使用char * ,char[] 等,使用std::string 替代 |
7 |
类对象 |
required |
子message |
自定义类,而不是系统类对象,需要包含在同一个文件里面, 再次没有递归处理其他包含的头文件。后续可能支持 类被映射为一个消息(只映射一次) 并再次映射为消息的成员(子消息) |
8 |
指针类型,支持2种指针: shared_ptr<T> weak_ptr<T> |
optional |
根据T的实际类型进行映射 |
T的类型为上面 编号1~7中的任意一种。 |
9 |
集合类型,包含一下几种: std::vector<T> std::list<T> std::set<T> std::multiset<T> |
required repeated |
bool include_${filename}字段 根据T的实际类型进行映射 |
包含一个bool类型的include字段,用于指示消息传递的过程中是 否包含本字段(protobuf repeated 字段存在二义性 ,在消息不包含repeated字段时,究竟时删除还是保留不变) T的类型为上面 编号1~8中的任意一种。 |
10 |
map类型,包含2种: std::map<KEY,VALUE> std::multimap<KEY,VALUE> |
optional repeated repeated |
boo include_${filename} reptead KEY ${filename}_key reptead VALUE ${filename}_value |
KEY和VALUE各自映射为一个字段。在传输过程中, 通过下标一一匹配. KEY,VALUE的类型为上面 编号1~8中的任意一种。 |
3. 自动化工具
工具使用Scala BNF语法进行构建,对C++头文件进行词法语法分析(主要分析类的声明和枚举的定义),并提取类的相关信息用于生成代码。
4.工具测试结果。