0

内部メッセージを解析して再シリアル化せずに、事前にエンコードされた内部メッセージを含むプロトコル バッファ メッセージを C++ で作成する方法はありますか?

明確にするために、次のメッセージ定義を検討してください。

message Inner {
    required int i = 1;
    // ... more fields ...
}

message Outer {
    repeated Inner inners = 1;
    // ... more fields ...
}

10 バイト配列のコレクションがあり、それぞれにエンコードされたバージョンの Inner が含まれているとします。10 個のインナーを含むアウターを作成したいと考えています。Outer には他のフィールドがあり、それ自体が他のメッセージに含まれる可能性があるため、手動でエンコードする必要はありません。事前にエンコードされた内部を直接コピーするプロトコル バッファを取得する方法はありますか?

4

1 に答える 1

1

クリーンな方法はありませんが、ハックな方法がいくつかあります。1 つは、次のような 2 番目のメッセージを定義することです。

message RawOuter {
    repeated bytes inners = 1;
    // ... same fields as Outer ...
}

RawOuterは、繰り返しフィールドが type から type に変更されたことをOuter除いて、と同じです。のエンコードされたインスタンスを入力してからシリアル化すると、解析されたバージョンで を構築した場合とまったく同じ結果が得られます。つまり、ネストされたメッセージのワイヤ フォーマットは、そのネストされたメッセージのシリアル化を含むフィールドのワイヤ フォーマットと同じです。これは、protobuf エンコーディングの面白い悪用可能な癖の 1 つです。innersInnerbytesinnersInnerRawOuterOuterbytes

ただし、このハックにはいくつかの問題があります。特に、他のプロトに埋め込まれたインスタンスを構築しようとしている場合は、うまく機能しません。これは、含まれているすべてのメッセージの 2 つのコピー (1 つは を使用し、もう 1Outerつは を使用) を保持したくない可能性があるためです。OuterRawOuter

Outer別のさらにハックなオプションは、エンコードされたメッセージをインスタンスのに挿入することUnknownFieldSetです。

Outer outer;
for (auto& inner: inners) {
  outer.mutable_unknown_fields()
      ->AddLengthDelimited(1, inner);
}

UnknownFieldSet、ファイルで定義されている既知のフィールド番号と一致しない、解析中に表示されるフィールドを格納することを目的としてい.protoます。これにより、プロトコルに新しいフィールドを追加するたびにプロキシを再コンパイルすることなく、単にメッセージを受信して​​別のサーバーに転送するプロキシ サーバーを作成できるようになるという考えです。ここでは、実際に既知のフィールドに対応する値をそれに貼り付けることで悪用していますが、実装は気付かないため、これらのフィールドは問題なく書き出されます。

このアプローチの主な問題は、値が実際には別の場所に隠されているためOuter、その間に他の誰かがあなたのインスタンスを検査すると、リストが空であるかのように見えることです。innersこれはかなり醜いハックであり、後であなたを悩ませることになるでしょう。パフォーマンスの違いを測定し、それが大きいことがわかった場合にのみお勧めします。

また、シリアライゼーション コードは常に未知のフィールドを最後に書き込みますが、既知のフィールドはフィールド番号順に書き込みます。パーサーは任意の順序を受け入れることになっていますが、解析されていないデータをハッシュ マップのキーなどとして使用していて、フィールドの順序を変更すると完全に壊れてしまう人がいることがあります。

ところで、文字列をコピーするのではなく所定の位置に交換することで、これらの両方のアプローチのパフォーマンスを向上させることができます。つまり、

raw_outer->add_inners()->swap(inner);

また

outer->mutable_unknown_fields()->AddLengthDelimited(1)->swap(inner);
于 2013-08-29T20:59:27.343 に答える