Protobuf-net 使用嵌套数据反序列化时出现无效的线型异常(C++ 到 C#)

Posted

技术标签:

【中文标题】Protobuf-net 使用嵌套数据反序列化时出现无效的线型异常(C++ 到 C#)【英文标题】:Invalid Wire Type Exception on Protobuf-net Deserialize with Nested Data (C++ to C#) 【发布时间】:2020-05-07 12:29:35 【问题描述】:

我得到了一个 C++ 应用程序(一个已构建的可执行文件和现在不构建的源代码),它使用生成的 proto 类来发送 protobuf 消息。我使用了用于生成其类的相同 .proto 文件,并在 C# 应用程序中生成了关联的类。目的是能够在 C# 端使用 protobuf-net 在这些应用程序之间接收和发送消息。请注意,两者都使用 proto2 格式。

只有简单类型(例如 int)成员的消息可以成功序列化和反序列化。但是,将具有嵌套消息类型的消息反序列化到我的 C# 应用程序中似乎存在问题,例如

message Outer 
    optional Inner = 1;


message Inner 
    optional float f = 1;

接收到的“外部”类型的消息将无法在 C# 中通过以下方式反序列化:

Serializer.Deserialize<T>(new MemoryStream(msg)); // msg is a byte[]

给出“无效的电线类型例外”。我点击了链接here,但是在查看了这些答案后,我没有发现任何与我的情况直接相关的明显内容。我 95% 确定源和目标生成的类是相同的,数据没有损坏,并且我正在反序列化为正确的类型。

我可以正确反序列化这样的嵌套类型吗? C++ 应用程序与使用 protobuf-net 的 C# 应用程序中类的生成方式(以及序列化方式)是否存在兼容性问题?

Here 是一个示例项目(在 VS 2019 中为 .NET Core 3.1 制作),它将重现该问题。

【问题讨论】:

我会从“相同”实例的两种语言生成字节数组并进行比较。鉴于该协议非常简单,因此应该可以看出差异所在。 @Voo 比较了一个简单类型的消息,字节是相同的。我只有 C++ 应用程序和源代码的构建版本,由于缺少依赖项,现在无法构建。我已经用wireshark 抓取了数据包,并将其转换为字节[] 进行比较。但是,因为我不知道嵌套类型的传入数据应该具有什么值,所以我不知道它是否会是一个有用的比较。我会四处挖掘,看看我是否能找出数据是什么。 FWIW,这应该可以工作,恕我直言。它似乎是 protobuf 应该能够做的事情的核心。你能发布一个完整的、独立的测试用例吗? @500-InternalServerError 我不确定你的意思;你想能够接受这个并自己运行它吗?或者您想了解更多关于当前问题的详细信息? 是的,如果我们都可以尝试您正在尝试的东西,那就太好了。 【参考方案1】:

我的传入数据有大约 50 个额外字节的“东西”我没有预料到(即不是消息头),它们不符合定义的消息格式,因此数据本质上是损坏的。从字节流中很难看出这一点。给出它的是我在 C# 端序列化的消息长度与我从 Wireshark 读取的消息的字节长度的差异。然后我查看了这些字节并找到了与我的序列化消息等效的字节。在。

为什么传入消息中有额外的“东西”是另一回事,但这是一个实现细节,所以我会认为这个问题已经结束。

如果它对处于类似情况的任何人有所帮助,我做了一个小测试循环,以继续尝试逐字节反序列化,直到它工作(可以改进但现在工作):

var rawBytes = msg.GetBytes(); // The raw incoming message
bool success = false;
OuterMsgType outer;
while (!success)

    try
    
        rawBytes = rawBytes.Skip(1).ToArray();
        outer = ProtoBuf.Serializer.Deserialize<OuterMsgType>(new MemoryStream(rawBytes));
        if (outer?.InnerMsg != null)
             success = true;
    
    catch (Exception e)
    
        // Wire type exception: Ignore it, don't care
    

【讨论】:

以上是关于Protobuf-net 使用嵌套数据反序列化时出现无效的线型异常(C++ 到 C#)的主要内容,如果未能解决你的问题,请参考以下文章

使用 protobuf-net 反序列化字典

使用 protobuf-net 反序列化不同的列表

我可以使用 Protobuf-net 对已用 Java 序列化的数据进行反序列化吗?

需要在运行时确定哪些类型 protobuf-net 可以序列化/反序列化

使用 protobuf-net 反序列化具有某些字段的派生类型的对象

Unity使用protobuf-net进行二进制序列化与反序列化