天天看點

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 = ;

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

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

required FileDescriptorSet proto_files = 1; 這個是一定不能少的,也是實作的關鍵,至于SelfDescribingMessage裡面其它的資料成員,可以根據自己的需求來加。

第二,實作自己通信協定接口的messages.proto檔案,這個檔案就是所有可擴充通信資料消息體,這裡簡單的寫幾個示例:

message ApplySettings {
    optional string language = ;
    optional string label = ;
    optional bool use_passphrase = ;
    optional bytes homescreen = ;
}

message Success {
    optional string message = ;    
}

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

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 = ; i < descriptor_set.file_size(); i++) {
        descriptor_pool.BuildFile(descriptor_set.file(i));
    }   
           

上面是運用的核心代碼,至于後面的應用就不在詳細寫了,需要用反射或者其它方法就自己行發揮了。

繼續閱讀