2012-08-16 11 views
26

私のサーバーでは、自己記述メッセージ(hereと定義されています)があります.btwはこれほど簡単ではありませんでした。すでに定義されているディスクリプタから新しいprotobufを動的に構築する方法は?

この時点では、これらの自己記述型メッセージからメッセージを作成することは問題ありません。私はFileDescriptorSetを取ることができ、それぞれFileDescriptorProtoを通り、DescriptorPoolにそれぞれを追加します(BuildFileを使用して、すべての定義されたFileDescriptorを与えます)。

ここからは、DPでインスタンス化されたDynamicMessageFactoryを持つFileDescriptorSetで定義されたメッセージを作成し、GetPrototypeを呼び出すことができます(SelfDescribedMessageがメッセージfull_name()を要求し、 DPのFindMessageTypeByNameメソッド、適切にエンコードされたメッセージプロトタイプを提供します)。

質問は、既に定義されたそれぞれのDescriptorまたはmessageをどのように取ることができ、定義されたすべてのメッセージを入れ子にしたメッセージを含む 'master'メッセージを動的に構築するのですか?これは、主にメッセージの現在の状態を保存するために使用されます。現在、私たちは、サーバー内の各メッセージのタイプをインスタンス化するだけで(異なるプログラム間で中央の状態を維持するために)これを処理しています。しかし、現在の状態を「保存」したいときは、それらを定義済みのようにディスクにストリームすることが強制されますhere。それらは一度に1つのメッセージ(サイズ接頭辞付き)でストリーミングされます。私たちは、別々のメッセージの安定したストリームではなく、1つのメッセージ(すべてを統治するメッセージ)を持っていたいと思います。これは、いったん完成したら(ネットワークベースの共有状態を最適化された簡単なシリアライゼーションを使って)、他のものにも使用できます。

私たちは既にクロスリンクされた記述子を持っているので、すでに定義されているメッセージからの「新しい」メッセージこれまでのところ、このソリューションは私たちに言いました。独自のDescriptorProtoを作成し、すでに定義されているDescriptorsの型の新しいフィールドを追加しようとしましたが、紛失してしまいました。また、拡張機能として追加することも考えられています(現時点では知られていません)。 DescriptorDatabaseを作成する必要がありますか(現時点ではその方法はわかりません)

洞察?


BitBucketのリンクexample source


この説明が役立ちますように。

すでに定義された一連のメッセージからメッセージを動的に作成しようとしています。すでに定義されているメッセージのセットは、公式のC++ protobufチュートリアル(コンパイルされた形式では利用できないこれらのメッセージ)で説明されている「自己記述」メソッドを使って作成されます。この新しく定義されたメッセージは、実行時に作成する必要があります。

各メッセージに対してストレートディスクリプタを使用しようとしましたが、FileDescriptorProtoを構築しようとしました。 DatabaseDescriptorメソッドを見てみました。どちらも運がありません。現在、これらの定義されたメッセージを別のメッセージの拡張機能として追加しようとしています(たとえコンパイル時に定義されたメッセージであっても、それらの記述子セットは拡張されていません)。

+0

すごい...いなくてもコメントが...ここです: – g19fanatic

+0

私が現時点で持っている問題は、拡張識別子の初期化です。 MessageTypeTraitsをメッセージタイプを記述するクラス(私自身のテンプレートマジックを行う必要があるかもしれません)に向けるクラスが必要ですが、まだ成功していません... – g19fanatic

+1

正直なところ、私はあなたの質問を3回読みました。まだ何を記述しているのか理解していません。私はこれがほとんどの読者に起こると思うので、返事を得られなかったのです。あなたはものを簡素化する必要があります。また、はるかに簡単な解決策が可能な、複雑すぎるものを構築しているような気がします。 – Codeguard

答えて

4

私は動的に.protoファイルを作成することで、この問題を解決することができましたし、 Importerをロードしてください。

唯一の要件は、各クライアントがprotoファイルを介して送信することです(実行時にはinit ...で必要とされません)。次に、各プロトファイルをtempディレクトリに保存します。可能であれば、必要なプロトファイルのすべてを保持する中央の場所にサーバーを指すだけです。

これは、最初にDiskSourceTreeを使用して実際のパスの場所をプログラム仮想パスにマップすることによって行われました。次に、.protoファイルをビルドして、送信されたすべてのプロトファイルをインポートし、「マスタメッセージ」にオプションのフィールドを定義します。

master.protoがディスクに保存された後、私はImporterでインポートします。 Importers DescriptorPoolとDynamicMessageFactoryを使用して、1つのメッセージの下でメッセージ全体を確実に生成することができます。私は、今夜または明日の後に私が何を記述しているかの例を載せる予定です。

このプロセスを改善する方法や、それをどうやって改善するかについてご意見がありましたら、ぜひお聞かせください。

他の誰かがより良い解決策を持っている場合に賞金が切れるまで、私はこの質問を未解決のままにしておきます。私がこれまでによどこ

{ 
    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; 
} 
+4

これを実装した例がありますか? – Dave

1

何文字列にすべてのメッセージをシリアライズし、マスタメッセージ(バイト)の文字列の順序を、ことについてラ

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

@ g19fanatic :これがあなたが探しているラインに沿っていないなら、あなたが達成しようとしていることを明確にすることができますか? – Managu

+0

これは現在行っているのとまったく同じですが、問題はすぐにそのメッセージのセットを解析することにあります。メッセージ間には固有の区切りがないので、各メッセージのサイズはuint32プレフィックスに格納されます。この接頭辞を使用して、各メッセージを個別に解析します。私たちがしようとしていることは、私たちがその後シリアライズするメッセージを一つだけ持つことです。それを解析する時間があるとき、繰り返しのgetnextsizeではなく、ただ1回の呼び出しで、次のメッセージを解析し、繰り返す。 – g19fanatic

+2

そう、 'serialized_sub_message'が' repeated'であるので、エンコード部分をプロトコルバッファに渡してください。だからそれはまだループです( 'dispatch_serialized_message(message_set.serialized_sub_message(i))')。しかし、コード化の詳細をワイヤに対処する必要はありません。 – Managu

5

あなたが protobuf::DynamicMessageFactory必要です。これは私が公開ソースを持っている唯一のものです...それは明らかに今コンパイルされません(ExtensionSetが最初に作成された最後まで)良いものです...他の2人はまだ私のところで失敗しています。 http://goo.gl/VJhnk
関連する問題