C++ Class Mapped Google Protocol Buffer Message (一)

2014-11-24 01:21:35 · 作者: · 浏览: 26

摘要
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
weak_ptr optional 根据T的实际类型进行映射 T的类型为上面 编号1~7中的任意一种。
9 集合类型,包含一下几种:
std::vector
std::list
std::set
std::multiset required
repeated bool include_${filename}字段
根据T的实际类型进行映射 包含一个bool类型的include字段,用于指示消息传递的过程中是
否包含本字段(protobuf repeated 字段存在二义性
,在消息不包含repeated字段时,究竟时删除还是保留不变)
T的类型为上面 编号1~8中的任意一种。
10 map类型,包含2种:
std::map
std::multimap 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.工具测试结果。
4.1 测试内容[cpp] view plaincopyprint
#ifndef __FOCUS_ENTITY_H__
#define __FOCUS_ENTITY_H__




#include
#include
#include

#include
#include
#include

#ifdef N_ODB
#include
#include
#include "Focus3800B.h"
#include "EntityBuild.h"
#endif
using std::tr1::shared_ptr;
using std::tr1::enable_shared_from_this;
using std::tr1::weak_ptr;
using std::tr1::dynamic_pointer_cast;

class CFocusEntity;
class CFocusZone;
class CFocusTerminal;
class CFocusUser;

inline shared_ptr toZone( const shared_ptr & en)
{
return dynamic_pointer_cast(en);
}
inline shared_ptr toTerminal( const shared_ptr & en)
{
return dynamic_pointer_cast(en);
}
inline shared_ptr toUser( const shared_ptr & en)
{
return dynamic_pointer_cast(en);
}
enum MsgNumPCtoTer {
terminal_config = 1,
network_basic_config = 2,
timenow_config = 3,
video_source_config = 16,
video_output_config = 17,
video_option_config = 18,
network_advanced_config = 19,
compatibility_config = 20,
network_dial_config = 21,
fire_wall_config = 22,
communication_config = 23,
video_config = 24,
e1_config = 25,
web_config = 26,
command_config = 27,
camera_select = 256,
camera_advance = 257,
camera_advance_active = 258,
camera_up = 259,
camera_down = 260,
camera_left = 261,
camera_right = 262,
camera_near = 263,
camera_far = 264,
floor_apply = 512,
chair_apply = 513,
chair_release = 514,
chair_viewed = 515,
timer_preview = 516,
auto_switch_time = 517,
broacast_local = 518,
force_exit = 519,
volume_set = 520,
m