閱讀目錄
回到頂部
在接收到 protobuf 資料之後,如何自動建立具體的 protobuf message 物件,再做反序列化。「自動」的意思主要有兩個方面:(1)當程式中新增乙個 protobuf message 型別時,這部分**不需要修改,不需要自己去註冊訊息型別,不需要重啟程序,只需要提供protobuf檔案;(2)當protobuf message修改後,這部分**不需要修改,不需要自己去註冊訊息型別,不需要重啟程序只需要提供修改後protobuf檔案。
回到頂部
protobuf的動態解析在google protobuf buffer官網並沒有什麼介紹。通過google出的一些參考文件可以知道,其實,google protobuf 本身具有很強的反射(reflection)功能,可以根據 type name 建立具體型別的 message 物件,我們直接利用即可,應該就可以滿足上面的需求。
實現可以參考**的文章《玩轉protocol buffers 》,裡面對protobuf的動態解析的原理做了詳細的介紹,在此我介紹一下protobuf class diagram。
大家通常關心和使用的是圖的左半部分:messagelite、message、generated message types (person, addressbook) 等,而較少注意到圖的右半部分:descriptor, descriptorpool, messagefactory。
上圖中,其關鍵作用的是 descriptor class,每個具體 message type 對應乙個 descriptor 物件。儘管我們沒有直接呼叫它的函式,但是descriptor在「根據 type name 建立具體型別的 message 物件」中扮演了重要的角色,起了橋梁作用。上圖的紅色箭頭描述了根據 type name 建立具體 message 物件的過程。
回到頂部
先直接上**,這個**來自於《玩轉protocol buffers 》:
#include
#include
#include
#include
#include
using namespace std;
using namespace google::protobuf;
using namespace google::protobuf::compiler;
int main(int argc,const char *argv)
disksourcetree sourcetree;
//look up .proto file in current directory
importer importer(&sourcetree, null);
//runtime compile foo.proto
importer.import("foo.proto");
const descriptor *descriptor = importer.pool()->
findmessagetypebyname("pair");
cout
// build a dynamic message by "pair" proto
dynamicmessagefactory factory;
const message *message = factory.getprototype(descriptor);
// create a real instance of "pair"
message *pair = message->new();
// write the "pair" instance by reflection
const reflection *reflection = pair->getreflection();
const fielddescriptor *field = null;
field = descriptor->findfieldbyname("key");
reflection->setstring(pair, field,"my key");
field = descriptor->findfieldbyname("value");
reflection->setuint32(pair, field, 1111);
cout
delete pair;
return0;
那我們就來看看上面的**
disksourcetree sourcetree;
//look up .proto file in current directory
importer importer(&sourcetree, null);
//runtime compile foo.proto
importer.import("foo.proto");
const descriptor *descriptor = importer.pool()->findmessagetypebyname("pair");
const message *message = factory.getprototype(descriptor);
message *pair = message->new();
const reflection *reflection = pair->getreflection();
const fielddescriptor *field = null;
field = descriptor->findfieldbyname("key");
reflection->setstring(pair, field,"my key");
field = descriptor->findfieldbyname("value");
reflection->setuint32(pair, field, 1111);
直接copy上面**看起來我們上面的需求就滿足了,只是唯一的缺點就是每次來個包載入一次配置檔案,當時覺得效能應該和讀取磁碟的效能差不多,但是經過測試效能極差,乙個程序每秒盡可以處理1000多個包,經過分析效能瓶頸不在磁碟,而在頻繁呼叫malloc和free上。
動態的message是我們用dynamicmessagefactory構造出來的,因此銷毀message必須用同乙個dynamicmessagefactory。 動態更新.proto檔案時,我們銷毀老的並使用新的dynamicmessagefactory,在銷毀dynamicmessagefactory之前,必須先刪除所有經過它構造的message。
原理:dynamicmessagefactory裡面包含dynamicmessage的共享資訊,析構dynamicmessage時需要用到。生存期必須保持descriptor>dynamicmessagefactory>dynamicmessage。
釋放順序必須是:釋放所有dynamicmessage,釋放dynamicmessagefactory,釋放importer。
回到頂部
資源釋放前,必須要了解資源的構造原理,通過構造原理反推釋放順序,這樣就少走彎路、甚至不走。
回到頂部
一種自動反射訊息型別的 google protobuf 網路傳輸方案
《玩轉protocol buffers 》
《google protocol buffer 的使用和原理》
如何解析超長的protobuf
在呼叫protobuf的parsefromstring str 方法時,預設情況下,如果str的長度 64mb,會返回失敗。這裡給出了解釋,主要是出於安全因素的考慮。可以通過settotalbyteslimit方法去除這個限制 google protobuf message req google p...
Groovy動態解析
a 前面需要說些什麼嗎?b 不需要嗎?a 需要嗎?解析方式一 通過指定的paths來初始化groovyscriptengine 通過指定的paths來初始化groovyscriptengine string paths groovyscriptengine gse new groovyscripte...
protobuf反射機制
參考 google protocol buffers protobuf 是一款非常優秀的庫,它定義了一種緊湊的可擴充套件二進位制訊息格式,特別適合網路資料傳輸。它為多種語言提供 binding,大大方便了分布式程式的開發,讓系統不再侷限於用某一種語言來編寫。在網路程式設計中使用 protobuf 需...