protobuf 自定义描述消息的实现

由于项目需要,最近在研究protobuf消息协议,关于protobuf协议,基础使用教程这里我就不想多说;度娘,谷哥都能找到大把,就不做太多解释。而关于protobuf动态自动反射消息的使用,这里可以参考陈硕的实现:http://blog.csdn.net/solstice/article/details/6300108

这里主要介绍一种在项目上使用的protobuf自己定义描述消息,FileDescriptorSet的使用,搜了好多文章大家只是一笔带过,至于怎么使用并没有给出详细说明。

项目场景:

由于开发时在通信接口协议层面中的.proto文件,可能会在后续扩展时更改,而按常规的使用方法,proto文件一旦更改后,整个程序又需要重新编译。那有没一种方法能在将proto文件像配置文件一样使用,与整个程序剥离开来。当接口层更新直接更新配置文件而应用程序不用再次编译更新? 答案当然是有的,就是使用protobuf的FileDescriptorSet来实现。

实现

首先,定义一个自己定义描述消息的config.proto文件,也就是动态自定义的关键,实例实现如下:

message SelfDescribingMessage {
  // Set of .proto files which define the type.
  required FileDescriptorSet proto_files = 1;

  // Name of the message type.  Must be defined by one of the files in
  // proto_files.
  required string type_name = 2;

  // The message data.
  required bytes message_data = 3;
}

required FileDescriptorSet proto_files = 1; 这个是一定不能少的,也是实现的关键,至于SelfDescribingMessage里面其它的数据成员,可以根据自己的需求来加。

第二,实现自己通信协议接口的messages.proto文件,这个文件就是所有可扩展通信数据消息体,这里简单的写几个示例:

message ApplySettings {
    optional string language = 1;
    optional string label = 2;
    optional bool use_passphrase = 3;
    optional bytes homescreen = 4;
}

message Success {
    optional string message = 1;    
}

message Failure {
    optional FailureType code = 1;  
    optional string message = 2;
}

message XXX {
    XXXX //这里是以后可能扩展的消息 
}

第三,用户protoc工具,将通信协议接口messages.proto生成配置文件。这里大家用的最多的是用protoc –cpp_out、–java_out、–python_out生成C++、Java或者Python相关的代码,但大家很少研究–descriptor_set_out=FILE这个参数–descriptor_set_out=FILE Writes a FileDescriptorSet (a protocol buffer,defined in descriptor.proto) containing all of the input files to FILE。
使用此参数时请配合google/protobuf/descriptor.proto文件一起使用protoc (path)/descriptor.proto messages.proto –descriptor_set_out=messages.cfg
到这一步就会将上面的messages.proto文件生成配置文件,这里也需要将config.proto文件按你本人需要生成C++、Java或者Python相关的代码。

最后,万事具备,只差东风了。现在我们来使用怎么用。

    // load config file
    std::string cpath("./messages.cfg");
    std::ifstream config(cpath, std::ios::in | std::ios::binary);

    // parse to FileDescriptorSet
    protobuf::pb::FileDescriptorSet descriptor_set;
    descriptor_set.ParseFromIstream(&config);

    DescriptorPool descriptor_pool;
    for (int i = 0; i < descriptor_set.file_size(); i++) {
        descriptor_pool.BuildFile(descriptor_set.file(i));
    }   

上面是运用的核心代码,至于后面的应用就不在详细写了,需要用反射或者其它方法就自己行发挥了。

猜你喜欢

转载自blog.csdn.net/ykevin0510/article/details/45651301