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

Yav*_*sov 15 .net c# protocol-buffers protobuf-net

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

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

我正在使用protobuf-net

Mar*_*ell 16

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

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

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

摘要:

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


Jon*_*eet 12

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

这在Protobuf文档中描述为"联合类型".


Dar*_*win 5

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

message MyCustomProtocol {
  required int32 protocolVersion = 1;
  required int32 messageType = 2;
  bytes data = 3;
}
Run Code Online (Sandbox Code Playgroud)

协议的一般规则是包含协议版本。一旦您拥有新老客户,您就会很高兴拥有它。