Frage Protobuf: Verschachteln einer Nachricht beliebigen Typs


Kurz gesagt, gibt es eine Möglichkeit, eine protobuf-Nachricht zu definieren, die eine andere Nachricht eines beliebigen Typs enthält? Etwas wie:

message OuterMsg {
    required int32 type = 1;
    required Message nestedMsg = 2; //Any sort of message can go here
}

Ich vermute, dass es einen Weg gibt, dies zu tun, weil in den verschiedenen protobuf-Implementierungen kompilierte Nachrichten von einem gemeinsamen ausgehen Message Basisklasse.

Ansonsten denke ich, ich muss eine gemeinsame Basis-Nachricht für alle möglichen Nachrichten erstellen:

message BaseNestedMessage {
    extensions 1 to max;
}

und dann

message OuterMessage {
    required int32 type = 1;
    required BaseNestedMessage nestedMsg = 2;
}

Ist das der einzige Weg dies zu erreichen?


6
2017-08-30 08:03


Ursprung


Antworten:


Nicht direkt, grundsätzlich; Protokollpuffer will sehr gerne die Struktur im Voraus wissen, und die Art der Nachricht ist nicht enthalten auf dem Draht. Das Gemeinsame Message Die Basisklasse ist ein Implementierungsdetail zum Bereitstellen von allgemeinem Installationscode - die Protokollpufferspezifikation enthält keine Vererbung.

Es gibt daher begrenzte Möglichkeiten:

  • Verwenden Sie unterschiedliche Feldnummern pro Nachrichtentyp
  • serialisieren Sie die Nachricht separat und fügen Sie sie als a ein bytes tippen Sie und übermitteln Sie das "was ist das?" Information getrennt (vermutlich ein Diskriminator / Enumeration)

Ich sollte auch beachten, dass einige Implementierungen kann bieten mehr Unterstützung dafür; protobuf-net (C # / .NET) unterstützt (getrennt) sowohl Vererbung als auch dynamische Nachrichtentypen (d. h. was Sie oben haben), aber Das ist in erster Linie für den Gebrauch von nur einer Bibliothek zu dieser einen Bibliothek gedacht. Weil das alles ist zusätzlich zu Die Spezifikation (die restlichen 100% sind in Bezug auf das Kabelformat gültig), kann es unnötig verwirrend sein, solche Daten von anderen Implementierungen zu interpretieren.


6
2017-08-30 08:16



Am beliebtesten ist es, optionale Felder für jeden Nachrichtentyp zu erstellen:

message UnionMessage
{
    optional MsgType1 msg1 = 1;
    optional MsgType2 msg2 = 2;
    optional MsgType3 msg3 = 3;
}

Diese Technik wird auch in der offiziellen Google-Dokumentation beschrieben und wird bei Implementierungen gut unterstützt: https://developers.google.com/protocol-buffers/docs/techniques#union


8
2017-08-30 08:48



Alternativ zu mehreren optional Felder, die oneof Schlüsselwort kann seit v2.6 von verwendet werden Protokollpuffer.

message UnionMessage {
  oneof data {
    string a = 1;
    bytes b = 2;
    int32 c = 3;
  }
}

1
2018-04-24 10:38