2012-08-16 22 views
26

在我的服務器上,我們收到自描述消息(如定義here ......這不是那麼容易,因爲在C++中沒有任何'好'的例子)。如何從一組已定義的描述符動態構建新的protobuf?

在這一點上,我沒有從這些自我描述的創建消息的問題。我可以使用FileDescriptorSet,通過每個FileDescriptorProto,將每個添加到DescriptorPool(使用BuildFile,這也給我每個定義的FileDescriptor)。

從這裏我可以創建任何在FileDescriptorSet中定義的消息,並使用DynamicMessageFactory實例化DP並調用GetPrototype(這很容易實現,因爲我們的SelfDescribedMessage需要消息full_name(),因此我們可以調用DP的FindMessageTypeByName方法,給我們正確編碼的消息原型)。

問題是,我如何獲取每個已定義的描述符或消息並動態地生成一個包含所有已定義消息的「主」消息作爲嵌套消息。這主要用於保存消息的當前狀態。目前我們只是通過實例化服務器中每種消息的類型來處理這個問題(以保持跨不同程序的中心狀態)。但是,當我們想要「保存」當前狀態時,我們不得不按照定義的here將它們流式傳輸到磁盤。它們每次只能傳輸一條消息(大小前綴)。我們希望有一條消息(一條來統治它們),而不是穩定的單獨消息流。這可以用於其他事情一旦制定出來(基於網絡的優化和簡單的序列化共享狀態)

由於我們已經有了交叉鏈接和定義的描述符,人們會認爲會有一種簡單的方法來構建來自那些已經定義的消息的'新'消息。到目前爲止,解決方案已經提到了我們。我們嘗試創建自己的DescriptorProto,並從已定義的描述符中添加新類型的字段,但卻迷失了方向(尚未深入探討)。我們也研究過可能將它們添加爲擴展名(目前未知如何實現)。我們是否需要創建我們自己的DescriptorDatabase(此時還不知道該怎麼做)?

任何見解?


鏈接example source在BitBucket上。


希望這個解釋會有所幫助。

我試圖從一組已定義的消息中動態構建消息。這組已經定義的消息是通過使用官方C++ protobuf教程中(簡要地)解釋的「自描述」方法創建的(即,這些消息在編譯後不可用)。這個新定義的消息將需要在運行時創建。

已嘗試使用每個消息的直接描述符並嘗試構建FileDescriptorProto。曾嘗試查看DatabaseDescriptor方法。兩者都沒有運氣。目前試圖將這些定義的消息添加爲另一個消息的擴展(甚至在編譯時,這些定義的消息及其'描述符集'未被分類爲擴展任何東西),這是示例代碼開始的地方。

+0

哇......甚至沒有評論...以下是我在哪裏爲止。這是我唯一擁有公共資源的人......它現在顯然不能編譯(直到最初創建ExtensionSet的那一端)......現在嘗試將擴展路由作爲另一個路由到目前爲止,還有兩個失敗了。 http://goo.gl/VJhnk – g19fanatic 2012-08-22 03:26:26

+0

我現在遇到的問題是擴展標識符的初始化。我需要一個類來指定MessageTypeTraits到一個描述消息類型的類(可能要做我自己的模板魔法?),但到目前爲止還沒有成功...... – g19fanatic 2012-08-22 03:29:21

+1

老實說,我讀了你的問題3次,並且仍然不明白你在描述什麼。我認爲這發生在大多數讀者身上,這就是爲什麼你沒有得到答覆。你確實需要簡化一些東西。此外,它真的感覺你正在構建一些複雜的東西,在那裏可以更容易的解決方案。 – Codeguard 2012-08-22 12:38:07

回答

4

我能夠動態地創建一個.proto文件來解決這個問題,加載一個Importer

唯一的要求是每個客戶端發送它的原始文件(只在init中需要...而不是在完全執行期間)。服務器然後將每個proto文件保存到一個臨時目錄。如果可能,另一種方法是將服務器指向一箇中心位置,該中心位置包含所有需要的proto文件。

這是通過首先使用DiskSourceTree將實際路徑位置映射到程序虛擬路徑位置來完成的。然後構建.proto文件以導入每個發送的原始文件,並在「主消息」中定義一個可選字段。

master.proto保存到磁盤後,我用導入器導入它。現在使用Importers DescriptorPool和一個DynamicMessageFactory,我可以在一條消息下可靠地生成整個消息。我將舉一個我今晚或明天將要描述的內容的例子。

如果任何人有任何關於如何使這個過程更好或如何做不同的建議,請說出來。

我將不會回答這個問題,直到賞金即將過期,以防其他人有更好的解決方案。

+4

你有沒有一個你如何實現它的例子? – Dave 2013-11-19 12:58:34

1

什麼所有的消息序列化爲字符串,使主消息(字節)串序列,一拉

message MessageSet 
{ 
    required FileDescriptorSet proto_files = 1; 
    repeated bytes serialized_sub_message = 2; 
} 
+0

@ g19fanatic :如果這不符合你的要求,你能澄清你想達到的目標嗎? – Managu 2012-08-22 14:19:03

+0

這正是我們目前正在做這件事的方式,但問題在於迅速將該組消息解析出來。由於消息之間沒有固有的分隔符,因此我們將每條消息的大小存儲在uint32前綴中。我們使用這個前綴來分別解析每條消息。我們試圖做的是隻有一條消息,然後我們序列化。當它解析出來的時候,它只需要調用一次而不是重複的getnextsize,解析下一條消息,重複一次。 – g19fanatic 2012-08-22 14:28:29

+2

好吧,把編碼部分交給協議緩衝區,'serialized_sub_message'被'重複'。所以它仍然是一個循環('dispatch_serialized_message(message_set.serialized_sub_message(i))'),但是你不必處理編碼的細節。 – Managu 2012-08-22 14:46:42

5

你需要一個protobuf::DynamicMessageFactory

{ 
    using namespace google; 

    protobuf::DynamicMessageFactory dmf; 
    protobuf::Message* actual_msg = dmf.GetPrototype(some_desc)->New(); 

    const protobuf::Reflection* refl = actual_msg->GetReflection(); 

    const protobuf::FieldDescriptor* fd = trip_desc->FindFieldByName("someField"); 
    refl->SetString(actual_msg, fd, "whee"); 

    ... 

    cout << actual_msg->DebugString() << endl; 
}