【问题标题】:Protobuf-net is incompatible with official google Protobuf for C++ (message encoding)Protobuf-net 与官方 google Protobuf for C++ 不兼容(消息编码)
【发布时间】:2012-12-24 10:46:26
【问题描述】:

我们在 .NET 中有一些(很多)类。我们使用protobuf-net 标记它们,并通过google original library 为C++ 代码端生成.proto 包装器。

所以我有一条消息(C++ DebugString() 在某个 EventBase 类上(在 .NET 中 EventCharacterMoved 继承 EventBase 而在 C++ 中我只是写入可选属性):

UserId: -2792
EventCharacterMoved {
  Coordinates {
    Position {
      X: 196.41913
      Y: 130
      Z: 213
    }
    Rotation {
      X: 207
      Y: 130
      Z: 213
    }
  }
  OldCoordinates {
    Position {
      X: 196.41913
      Y: 130
      Z: 213
    }
    Rotation {
      X: 207
      Y: 130
      Z: 213
    }
  }
}

(来自这样的 .proto 文件)

message Coordinates {
   optional TreeFloat Position = 1;
   optional TreeFloat Rotation = 2;
}
message EventBase {
   optional int32 UserId = 10 [default = 0];
   // the following represent sub-types; at most 1 should have a value
   optional EventCharacterMoved EventCharacterMoved = 15;
}
message EventCharacterMoved {
   optional Coordinates Coordinates = 100;
   optional Coordinates OldCoordinates = 101;
}
message TreeFloat {
   optional float X = 1 [default = 0];
   optional float Y = 2 [default = 0];
   optional float Z = 3 [default = 0];
}

在 C++ 中,我发送这个,我们从 .NET 发送相同的消息内容。

C++ 代码可以解析 C++ 编码的消息以及 .NET 编码的消息。 .NET 代码只能解析 .NET 消息。

通过网络我们得到 87 个字节(与 .Net fileC++ file 大小相同)但内容不同:

正如您所见,它相似但又不一样。 由于这种差异,CPP 代码可以读取 .NET C# 消息,而 .NET 无法读取 CPP 消息

在反序列化的代码中我们得到:

发生了“System.InvalidCastException”类型的未处理异常 在TestProto.exe中

附加信息:无法转换类型的对象 'TestProto.EventBase' 输入 'TestProto.EventCharacterMoved'。

在代码中:

using (var inputStream = File.Open(@"./cpp_in.bin", FileMode.Open, FileAccess.Read)) {
    var ecm = Serializer.Deserialize<EventCharacterMoved>(inputStream);
}

让我们看看(正如jpa 在他的评论中提到的)protoc --decode_raw 选项:

这可能与我的 CPP 包装器使用最新的 google protobuf 版本有关,而 protobuf-net 可能使用一些较旧的编码格式或类似的东西......

所以我想知道如何让 .NET protobuf 读取 C++ 消息(让 tham 能够解码相同的东西)?

或者至少如何使原始 google protobuf 以与 .NET protobuf 相同的方式编码?

对于那些真正感兴趣并想参与其中的人zipped bundle with simplified example (VS 2010 solutions for C++ and C# code included)

【问题讨论】:

  • 能否请您出示您用于c++版本的.proto,以及c#中使用的合同。它们应该完全兼容,如果它们不兼容,我会感到非常惊讶。我没有手动处理这 2 个二进制片段(不是在 PC 上,如果我今天启动 PC,我会被妻子谋杀),但发布使用的合同会对我有很大帮助。此外,protobuf 并不要求保证字段顺序(多个不同的文件可以包含相同的数据)——尽管实际上它通常是按升序编写的。
  • 另外,让我知道mention的继承是否是protobuf定义的一部分 - 意思是:EventBase也是合同。
  • 提供示例,简化原始代码。
  • 通过protoc --decode_raw同时运行net_in.bin和cpp_in.bin,我看到唯一的区别是字段10(UserId)是先写还是最后写。 C++ 首先发出它,.NET 出于某种原因最后发出(通常它们应该按标签按数字顺序排列)。但不确定是什么导致了实际问题。
  • 我的行动方案(如果我现在有时间的话)将检查 ProtoBuf.net 的源并确保它以正确的顺序编码标签。

标签: c# c++ .net protocol-buffers protobuf-net


【解决方案1】:

编辑;这应该在 r616 及更高版本中修复。


我终于有机会看看这个(对于延迟表示歉意,但社会季节性假期需求干预了)。我明白现在发生了什么。

基本上,数据在理论上是相同的;这实际上归结为字段排序。从技术上讲,字段通常按升序编写,但可以按任何顺序编写。关于 protobuf-net;对于不涉及继承的类型,无论顺序如何,它都可以正常工作。 protobuf 规范没有定义继承,因此 protobuf-net 添加了对继承的支持(由于不断的需求)另外到规范中。作为一个实现特性,它首先写入子类信息(即字段15,子类型,写在字段10之前)。目前,在反序列化过程中,它也期望首先获得子类型信息。这很少对任何人产生影响,因为由于 protobuf-net 是唯一使用这种继承的实现,因此继承功能的使用大多只在 protobuf-net 到 protobuf-net 的使用中看到。

在您的情况下,您使用 .proto 与 CPP 进行互操作;这意味着 CPP 代码将能够消费到 protobuf-net 数据,但它可能有一个相反的类型转换异常(基本上,它在获取第一个数据字段时开始构造具体类型)。

尽管很少出现问题,但这是需要解决的问题。我可以试着在今天晚些时候或明天看看这个。

选项:

  • 确保子类型字段始终低于任何数据字段
  • 如果您知道它需要子类型,请使用 Merge API 并传入所需类型的现有新对象 - 这将正确填充现有对象
  • 等待一两天(希望如此!)使用 build r616 或更高版本进行正确修复
  • 在使用互操作时避免继承(和其他特定于实现的功能)
    • 请注意,您可以通过封装对相同的数据进行建模,并且它会正常工作;具体来说,这里的问题是具体类型的创建
  • 在从 CPP 站点构建数据时,通过将其写成两部分来使用不合理的长度(意思是:我不认为这是一个实际的解决方案):
    • 先用 EventCharacterMoved 数据写入EventBase,然后序列化;现在在一个单独的模型中写一个 EventBasejust TreeFloat 数据,并序列化;这将模拟按所需顺序编写它们(protobuf 流是可附加的)- 不漂亮

【讨论】:

    【解决方案2】:

    这看起来与http://code.google.com/p/protobuf-net/issues/detail?id=299http://code.google.com/p/protobuf-net/issues/detail?id=331 中提到的问题非常相似,据称这些问题已由http://code.google.com/p/protobuf-net/source/detail?r=595 修复

    您使用的 .NET protobuf 版本是否足够新以包含该修复程序?

    【讨论】:

    • 我们用户版本来自 protobuf-net r602.zip protobuf-net r602 精选 protobuf-net 下载。我们还联系了 Marc Gravell,他承诺他会尽快修复这个错误。=) 你也可以下载我们提供的示例项目并尝试一下。=)) mx 和 hny=)))
    • @myWallJSON 很酷,很高兴你能胜任!实际上,我没有任何带有 .Net 的东西,所以我无法真正尝试。您的问题和错误都出现在(对我来说没用)导致谷歌搜索的结果,所以我想我会利用随机的偶然性,看看它是否是您正在寻找的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多