[英]Protocol buffers detect type from raw message
Is it possible to detect the type of a raw protocol buffer message (in byte[]) 是否可以检测原始协议缓冲区消息的类型(在byte []中)
I have a situation where an endpoint can receive different messages and I need to be able to detect the type before I can deserialize it. 我有一种情况,端点可以接收不同的消息,我需要能够检测类型,然后才能反序列化它。
I am using protobuf-net 我正在使用protobuf-net
You can't detect the type in isolation, since the protobuf spec doesn't add any data to the stream for this; 您不能孤立地检测类型,因为protobuf规范不会为此向流添加任何数据; however, there are a number of ways of making this easy, depending on the context:
但是,根据具体情况,有很多方法可以简化:
the last approach is actually very valuable in the case of raw TCP streams; 在原始TCP流的情况下,最后一种方法实际上非常有价值; this is on the wire identical to the union type, but with a different implementation;
这与导线类型相同,但具有不同的实现; by deciding in advance that 1=Foo, 2=Bar etc (exactly as you do for the union type approach), you can use
SerializeWithLengthPrefix
to write (specifying the 1/2/etc as the field number), and the non-generic TryDeserializeWithLengthPrefix
to read (this is under Serializer.NonGeneric in the v1 API, or on the TypeModel in the v2 API), you can provide a type-map that resolves the numbers back to types, and hence deserialize the correct type. 通过预先确定1 = Foo,2 = Bar等(与联合类型方法完全相同),您可以使用
SerializeWithLengthPrefix
进行写入(将1/2 / etc指定为字段编号),以及非泛型要读取TryDeserializeWithLengthPrefix
(这是在v1 API中的Serializer.NonGeneric下,或者在v2 API中的TypeModel下),您可以提供一个类型映射,将数字解析回类型,从而反序列化正确的类型。 And to pre-empt the question "why is this useful with TCP streams?" 并预先解决“为什么这对TCP流有用?” - because: in an ongoing TCP stream you need to use the
WithLengthPrefix
methods anyway , to avoid over-reading the stream; - 因为:在正在进行的TCP流中, 无论如何都需要使用
WithLengthPrefix
方法,以避免过度读取流; so you might as well get the type identifier for free! 所以你不妨免费获得类型标识符!
summary: 摘要:
One typical option is to have a wrapper message to act as an "option type" or discriminated union. 一个典型的选择是使包装器消息充当“选项类型”或区别联合。 You could have an enum (one per message type) and a message containing a field with the message type in, and then one optional field per message type.
您可以拥有一个枚举(每个消息类型一个)和一个包含消息类型的字段的消息,然后每个消息类型一个可选字段。
This is described in the Protobuf documentation as a "union type" . 这在Protobuf文档中描述为“联合类型” 。
You could wrap it like this. 你可以像这样包装它。 Where data would hold the actual message.
数据将保存实际消息的位置。
message MyCustomProtocol {
required int32 protocolVersion = 1;
required int32 messageType = 2;
bytes data = 3;
}
A general rule for protocols is to include a protocol version. 协议的一般规则是包括协议版本。 You will be very happy to have it once you have old and new clients.
一旦有新老客户,您将非常乐意拥有它。
You could use a technique called Self Describing Messages . 您可以使用一种名为Self Describing Messages的技术。 It can be used to generate a set of .proto files describing each message type encoded as 'any' within a wrapper.
它可用于生成一组.proto文件,这些文件描述在包装器中编码为“任何”的每种消息类型。 An example from the docs:
来自文档的一个例子:
syntax = "proto3";
import "google/protobuf/any.proto";
import "google/protobuf/descriptor.proto";
message SelfDescribingMessage {
// Set of FileDescriptorProtos which describe the type and its dependencies.
google.protobuf.FileDescriptorSet descriptor_set = 1;
// The message and its type, encoded as an Any message.
google.protobuf.Any message = 2;
}
It should be noted that native support for these messages at the time of writing this response is only available in C++ and Java. 应该注意的是,在编写此响应时对这些消息的本机支持仅在C ++和Java中可用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.