繁体   English   中英

协议缓冲区从原始消息中检测类型

[英]Protocol buffers detect type from raw message

是否可以检测原始协议缓冲区消息的类型(在byte []中)

我有一种情况,端点可以接收不同的消息,我需要能够检测类型,然后才能反序列化它。

我正在使用protobuf-net

您不能孤立地检测类型,因为protobuf规范不会为此向流添加任何数据; 但是,根据具体情况,有很多方法可以简化:

  • 联合类型(如Jon所述)涵盖了一系列场景
  • 继承(protobuf-net specific)可以是通用的 - 你可以有一个基本消息类型,以及任意数量的具体消息类型
  • 您可以使用前缀来指示传入类型

在原始TCP流的情况下,最后一种方法实际上非常有价值; 与导线类型相同,但具有不同的实现; 通过预先确定1 = Foo,2 = Bar等(与联合类型方法完全相同),您可以使用SerializeWithLengthPrefix进行写入(将1/2 / etc指定为字段编号),以及非泛型要读取TryDeserializeWithLengthPrefix (这是在v1 API中的Serializer.NonGeneric下,或者在v2 API中的TypeModel下),您可以提供一个类型映射,将数字解析回类型,从而反序列化正确的类型。 并预先解决“为什么这对TCP流有用?” - 因为:在正在进行的TCP流中, 无论如何需要使用WithLengthPrefix方法,以避免过度读取流; 所以你不妨免费获得类型标识符!

摘要:

  • 联合类型:易于实施; 只有下方必须检查哪些属性是非空的
  • 继承:易于实现; 可以使用多态或鉴别器来处理“现在怎么办?”
  • 类型前缀:实现起来有点繁琐,但允许更多的灵活性,并且在TCP流上没有任何开销

一个典型的选择是使包装器消息充当“选项类型”或区别联合。 您可以拥有一个枚举(每个消息类型一个)和一个包含消息类型的字段的消息,然后每个消息类型一个可选字段。

这在Protobuf文档中描述为“联合类型”

你可以像这样包装它。 数据将保存实际消息的位置。

message MyCustomProtocol {
  required int32 protocolVersion = 1;
  required int32 messageType = 2;
  bytes data = 3;
}

协议的一般规则是包括协议版本。 一旦有新老客户,您将非常乐意拥有它。

您可以使用一种名为Self Describing Messages的技术。 它可用于生成一组.proto文件,这些文件描述在包装器中编码为“任何”的每种消息类型。 来自文档的一个例子:

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;
}

应该注意的是,在编写此响应时对这些消息的本机支持仅在C ++和Java中可用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM