1. 程式人生 > >C++ Class Mapped Google Protocol Buffer Message

C++ Class Mapped Google Protocol Buffer Message

摘要 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.工具測試結果。  4.1 測試內容 #ifndef __FOCUS_ENTITY_H__ #define __FOCUS_ENTITY_H__         #include <string> #include <memory> #include <set>   #include <odb/database.hxx> #include <odb/tr1/memory.hxx> #include <odb/callback.hxx>   #ifdef N_ODB #include <Mutex.h> #include <functional> #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<CFocusZone> toZone( const shared_ptr<CFocusEntity> & en) {     return dynamic_pointer_cast<CFocusZone,CFocusEntity>(en); } inline shared_ptr<CFocusTerminal> toTerminal( const shared_ptr<CFocusEntity> & en) {     return dynamic_pointer_cast<CFocusTerminal,CFocusEntity>(en); } inline shared_ptr<CFocusUser> toUser( const shared_ptr<CFocusEntity> & en) {      return dynamic_pointer_cast<CFocusUser,CFocusEntity>(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,   mute_in_set = 521,   mute_out_set = 522,   dualstream_set = 523,   conf_call_set = 524,   accept_in_call = 525,   reject_in_call = 526,   conf_drop = 527,   phone_modify = 528,   phone_add = 529,   feec_apply = 530,   phone_histroy_del = 531,   picture_show = 532,   near_key = 533,   far_key = 534,   OK_key = 535,   Ping = 768,   video_loop = 769,   restore = 770,   out_test = 771,   login_console = 1024,   logout_console = 1025,   restart = 1281 };   #pragma db object polymorphic callback(dbevent) table("tblEntity") class CFocusEntity : public enable_shared_from_this<CFocusEntity> {     friend class odb::access; public:      CFocusEntity();     virtual ~CFocusEntity();     unsigned int GetId() const { return id_; }     void SetId(unsigned int val) { id_ = val; }       const std::string & GetName() const { return name_; }     void SetName(const std::string & val) { name_ = val; }       shared_ptr<CFocusZone> GetParent() const;     void SetParent(const shared_ptr<CFocusZone> & val) { parent_ = val; }       virtual void dbevent( odb::callback_event e, odb::database& db );     virtual void dbevent( odb::callback_event e, odb::database& db ) const;       bool persist();     bool update();     bool erase(); #ifdef N_ODB     virtual shared_ptr<CProtobufEntityBuild> CreateBuild() { return nullptr;} #endif     void SendIndication();   protected:       void InternalSendIndcation(); private: #pragma db id auto     unsigned int id_;        std::string  name_;         weak_ptr<CFocusZone> parent_;    };   #pragma  db object  callback(dbevent) table("tblZone") class CFocusZone : public CFocusEntity {     friend class odb::access; public:     CFocusZone();     ~CFocusZone();       void AddEntity( const shared_ptr<CFocusEntity> & en);     void DelEntity( const shared_ptr<CFocusEntity> & en );         void dbevent( odb::callback_event e, odb::database& db );     void dbevent( odb::callback_event e, odb::database& db ) const;       shared_ptr<CFocusEntity> FindEntity( unsigned int id, bool recursive = false) ;     shared_ptr<CFocusEntity> FindEntity( const std::string & name, bool recursive = false) ; #ifdef N_ODB     void foreach( const std::function<void( const shared_ptr<CFocusEntity> & ) > & callback  , bool recursive = false, bool isCallItself = false);     virtual shared_ptr<CProtobufEntityBuild> CreateBuild();   #endif         static void SetRootZone( const shared_ptr<CFocusZone> & rootZone_);       static const shared_ptr<CFocusZone> & GetRootZone(); protected:     static shared_ptr<CFocusZone> rootZone; private: #pragma db inverse(parent_)     std::set< shared_ptr<CFocusEntity> > members_;         std::set< int > int_members_;               std::set< CFocusEntity > raw_members_;                  std::map< int ,shared_ptr<CFocusEntity> > map_members_;         std::map< int ,int > map_int_members_;               std::map< int ,CFocusEntity > map_raw_members_;              #ifdef N_ODB     mutable dv::CMutex members_mutex; #endif   };   #pragma db object callback(dbevent) table("tblTerminal") class CFocusTerminal : public CFocusEntity {     friend class odb::access; public:     CFocusTerminal();     ~CFocusTerminal();       const std::string & GetAddress() const { return address_; }     void SetAddress(const std::string & val) { address_ = val; }       unsigned short GetPort() const { return port_; }     void SetPort(unsigned short val) { port_ = val; }       const std::string & GetUsername() const { return username_; }     void SetUsername(const std::string & val) { username_ = val; }       const std::string & GetPassword() const { return password_; }     void SetPassword(const std::string & val) { password_ = val; }             void dbevent( odb::callback_event e, odb::database& db );     void dbevent( odb::callback_event e, odb::database& db ) const;       void keepalive_init();              void clear_status();       void send_keepalive();       void remote_login();       void release_connect();       bool IsOnline() const { return recv_service_ok_;} #ifdef N_ODB     void OnRecvMessage( T_Message &recvMsg );    // bool IsDualEnable() const { return IsOnline () && dual_stream_status_ ;}     bool IsLogin() const { return remote_login_ok_; }     //bool IsAdmin() const { return remote_login_ok_ && adminstartor_ok_;}     virtual shared_ptr<CProtobufEntityBuild> CreateBuild();     void SetDualEnable( DualLevel level );     //bool IsInConfing() const { return conf_status_.ConfStatus > 0 ? true : false;}     void SetCommand( unsigned long ulCommand);     void DisConnect();     const T_InformTerConfig & GetTerConfig() const { return ter_config_;}     const T_InformSysStatus & GetSysStatus() const { return sys_status_;}     const T_InformConfStatus & GetConfStatus() const { return conf_status_;}     //const T_InformVideoConfig & GetVideoConfig() const { return video_config_; }     const T_VideoOption & GetVideoOption() const { return video_option_; }     const T_SetupSoftware & GetSoftwareVersion() const { return software_version_; }     void clear_resource();     bool CanSendMediaInfo() const { return is_recv_sys_status_;}       unsigned int GetValveRecvRate() const { return valveRecvRate_; }     void SetValveRecvRate(unsigned int val) { valveRecvRate_ = val; }       unsigned int GetValveSendRate() const { return valveSendRate_; }     void SetValveSendRate(unsigned int val) { valveSendRate_ = val; }       unsigned int GetValveRecvFrame() const { return valveRecvFrame_; }     void SetValveRecvFrame(unsigned int val) { valveRecvFrame_ = val; }       unsigned int GetValveSendFrame() const { return valveSendFrame_; }     void SetValveSendFrame(unsigned int val) { valveSendFrame_ = val; }       unsigned int GetValveLostRate() const { return valveLostRate_; }     void SetValveLostRate(unsigned int val) { valveLostRate_ = val; } #endif     const std::string & GetH323id() const { return h323id_; }    // void SetH323id(std::string val) { h323id_ = val; }       const std::string & GetE164() const { return e164_; }     //void SetE164(std::string val) { e164_ = val; }     unsigned int GetNo() const { return No_; }     void SetNo(unsigned int val) { No_ = val; }       const std::string & GetContacter() const { return contacter_; }     void SetContacter(const std::string &  val) { contacter_ = val; }       const std::string &  GetPhone() const { return phone_; }     void SetPhone(const std::string &  val) { phone_ = val; } private:     std::string    address_;         unsigned short port_;     std::string username_;     std::string password_;     unsigned int No_;        std::string contacter_;        std::string phone_;     unsigned int valveRecvRate_ ;     unsigned int valveSendRate_;     unsigned int valveRecvFrame_;     unsigned int valveSendFrame_;     unsigned int valveLostRate_;    #pragma db transient     unsigned int connect_id_; #pragma db transient     unsigned int timer_id_; #pragma db transient     bool  recv_service_ok_; #pragma db transient     bool  remote_login_ok_; #pragma db transient     bool  adminstartor_ok_; #pragma db transient     bool dual_stream_status_; #pragma db transient     std::string h323id_;    #pragma db transient     std::string e164_;      #ifdef N_ODB     T_InformTerConfig ter_config_;     T_InformSysStatus sys_status_;     T_InformConfStatus conf_status_;     T_VideoOption video_option_;     T_Message     lastRecvMsg_;     T_SetupSoftware software_version_;     bool is_recv_sys_status_; #endif };   #pragma db object callback(dbevent) table("tblUser") class CFocusUser : public CFocusEntity {     friend class odb::access; public:      CFocusUser();     ~CFocusUser();       const std::string & GetPassword() const { return password_; }     void SetPassword(const std::string & val) { password_ = val; }       void dbevent( odb::callback_event e, odb::database& db );     void dbevent( odb::callback_event e, odb::database& db ) const; #ifdef N_ODB     virtual shared_ptr<CProtobufEntityBuild> CreateBuild(); #endif protected:     private:     std::string password_; }; #endif

4.2輸出結果 package pbmsg;  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; mute_in_set = 521; mute_out_set = 522; dualstream_set = 523; conf_call_set = 524; accept_in_call = 525; reject_in_call = 526; conf_drop = 527; phone_modify = 528; phone_add = 529; feec_apply = 530; phone_histroy_del = 531; picture_show = 532; near_key = 533; far_key = 534; OK_key = 535; Ping = 768; video_loop = 769; restore = 770; out_test = 771; login_console = 1024; logout_console = 1025; restart = 1281; };   message CFocusEntity {   optional fixed32 id = 1; required bytes name = 2;  optional CFocusEntity parent = 3; };          message CFocusZone { required CFocusEntity base = 1;   optional bool include_members = 2; repeated CFocusEntity members =3;            optional bool include_int_members = 4; repeated sfixed32 int_members =5;            optional bool include_raw_members = 6; repeated CFocusEntity raw_members =7;            optional bool include_map_members = 8; repeated sfixed32 map_members_key =9; repeated CFocusEntity map_members_value =10;            optional bool include_map_int_members = 11; repeated sfixed32 map_int_members_key =12; repeated sfixed32 map_int_members_value =13;            optional bool include_map_raw_members = 14; repeated sfixed32 map_raw_members_key =15; repeated CFocusEntity map_raw_members_value =16;          };          message CFocusTerminal { required CFocusEntity base = 1; required bytes address = 2;  optional uint32 port = 3; required bytes username = 4;  required bytes password = 5;  optional fixed32 No = 6; required bytes contacter = 7;  required bytes phone = 8;  optional fixed32 valveRecvRate = 9; optional fixed32 valveSendRate = 10; optional fixed32 valveRecvFrame = 11; optional fixed32 valveSendFrame = 12; optional fixed32 valveLostRate = 13; optional fixed32 connect_id = 14; optional fixed32 timer_id = 15; optional bool recv_service_ok = 16; optional bool remote_login_ok = 17; optional bool adminstartor_ok = 18; optional bool dual_stream_status = 19; required bytes h323id = 20;  required bytes e164 = 21;  };          message CFocusUser { required CFocusEntity base = 1; required bytes password = 2;  };               Process finished with exit code 0

---------------------  原文:https://blog.csdn.net/love_newzai/article/details/9013183