29

私のサーバーでは、自己記述型メッセージを受信します(ここで定義されているように、c ++には「良い」例がないため、これはそれほど簡単ではありませんでした)。

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

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

問題は、すでに定義されている各記述子またはメッセージを取得し、定義されたすべてのメッセージをネストされたメッセージとして含む「マスター」メッセージを動的に構築するにはどうすればよいかということです。これは主に、メッセージの現在の状態を保存するために使用されます。現在、サーバー内の各メッセージのタイプをインスタンス化するだけでこれを処理しています(さまざまなプログラム間で中央の状態を維持するため)。しかし、現在の状態を「保存」したい場合は、ここで定義されているように、それらをディスクにストリーミングする必要があります。一度に1つのメッセージがストリーミングされます(サイズプレフィックス付き)。個別のメッセージの安定したストリームではなく、1つのメッセージ(すべてを支配する1つ)が必要です。これは、一度解決されると他のことに使用できます(最適化された簡単なシリアル化を備えたネットワークベースの共有状態)

すでにクロスリンクされ定義された記述子があるので、それらのすでに定義されたものから「新しい」メッセージを構築する簡単な方法があると思うでしょう。これまでのところ、解決策は私たちをほのめかしています。独自のDescriptorProtoを作成し、すでに定義されているDescriptorsからこのタイプの新しいフィールドを追加しようとしましたが、迷子になりました(まだこれについて深く掘り下げていません)。また、それらを拡張機能として追加する可能性も検討しました(現時点ではその方法は不明です)。独自のDescriptorDatabaseを作成する必要がありますか(現時点ではその方法も不明です)?

洞察はありますか?


BitBucketのリンクされたサンプルソース。


この説明がお役に立てば幸いです。

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

各メッセージにストレート記述子を使用してみて、FileDescriptorProtoを作成しようとしました。DatabaseDescriptorメソッドを調べてみました。どちらも運がない。現在、これらの定義されたメッセージを別のメッセージの拡張として追加しようとしています(コンパイル時にこれらの定義されたメッセージであり、それらの「descriptor-set」は拡張として分類されませんでした)。ここからサンプルコードが始まります。

4

3 に答える 3

6

あなたが必要です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;
}
于 2014-04-17T01:17:54.940 に答える
5

.protoファイルを動的に作成し、それをImporterでロードすることで、この問題を解決することができました。

唯一の要件は、各クライアントがそのprotoファイルを介して送信することです(初期化時にのみ必要です...完全な実行中ではありません)。次に、サーバーは各protoファイルを一時ディレクトリに保存します。可能であれば、必要なすべてのprotoファイルを保持する中央の場所にサーバーを指定することもできます。

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

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

このプロセスを改善する方法や別の方法を提案する人がいる場合は、そのように言ってください。

他の誰かがより良い解決策を持っている場合に備えて、バウンティが期限切れになるまで、この質問には答えないままにしておきます。

于 2012-08-22T18:09:41.820 に答える
1

すべてのメッセージを文字列にシリアル化し、マスターメッセージを(バイト)文字列のシーケンスにするのはどうですか?

message MessageSet
{
  required FileDescriptorSet proto_files = 1;
  repeated bytes serialized_sub_message = 2;
}
于 2012-08-22T14:16:38.880 に答える