在C#中解析原始的协议缓冲区字节流

3
给定一个使用协议缓冲编码的Streambyte[],但不知道对象类型本身,我们如何打印消息的框架?使用案例是用于基于protobuf的IO调试,以进行根本原因分析。
如果存在可以解析来自二进制文件的原始协议缓冲区字节流的现有工具-那将是很好的!另一种选择可能是使用ProtoBuf.NET类ProtoReader()继续运行,直到我们遇到错误,但是ProtoReader()的使用方法并不清楚。我从下面开始,但找不到有关如何使用ProtoReader类实际执行此操作的良好文档。项目的源代码也不是很简单明了...因此希望得到一些提示/帮助。
using (var fs = File.OpenRead(filePath))
{
    using (var pr = new ProtoReader(fs, TypeModel.Create(), null))
    {
        // Use ProtoReader to march through the bytes
        // Printing field number, type, size and payload values/bytes
    }
}
1个回答

4

首先,需要注意的是,Google的“protoc”命令行工具有选项可以尝试在没有模式信息的情况下分解原始消息。使用protobuf-net,您可以像下面这样做 - 但我需要强调的是,在没有模式的情况下,格式是不明确的:存在比“wire types”(实际编码格式)更多的数据类型/格式。这里我只显示了可能的解释,但有其他解析相同数据的方法。

static void WriteTree(ProtoReader reader)
{
    while (reader.ReadFieldHeader() > 0)
    {
        Console.WriteLine(reader.FieldNumber);
        Console.WriteLine(reader.WireType);
        switch (reader.WireType)
        {
            case WireType.Variant:
                // warning: this appear to be wrong if the 
                // value was written signed ("zigzag") - to
                // read zigzag, add: pr.Hint(WireType.SignedVariant);
                Console.WriteLine(reader.ReadInt64());
                break;
            case WireType.String:
                // note: "string" here just means "some bytes"; could
                // be UTF-8, could be a BLOB, could be a "packed array",
                // or could be sub-object(s); showing UTF-8 for simplicity
                Console.WriteLine(reader.ReadString());
                break;
            case WireType.Fixed32:
                // could be an integer, but probably floating point
                Console.WriteLine(reader.ReadSingle());
                break;
            case WireType.Fixed64:
                // could be an integer, but probably floating point
                Console.WriteLine(reader.ReadDouble());
                break;
            case WireType.StartGroup:
                // one of 2 sub-object formats
                var tok = ProtoReader.StartSubItem(reader);
                WriteTree(reader);
                ProtoReader.EndSubItem(tok, reader);
                break;
            default:
                reader.SkipField();
                break;
        }
    }
}

在v3中,或者参考这个链接:https://stackoverflow.com/a/64621670/23354


马克,太好了。鉴于您的经验,您能否建议使用Google的protoc?我找不到关于它的文档。我确实使用了--decode_raw,但不清楚如何传递二进制数组(例如:.bin文件)... - user2925445
1
无法解析输入。即使ProtoBuf可以正常读取二进制文件/流,但仍然出现了与之前一样的protoc错误。我以为可能是缺少某些格式或参数,但现在看来不是这样。算了,我就用ProtoBuf.NET代码吧。谢谢! - user2925445
如果您认为数据是子对象,则基本上可以使用StartGroup中显示的完全相同的代码,即StartSubItemWriteTreeEndSubItem。更正确的方法是将数据作为byte[]ProtoReader.AppendBytes)获取,然后测试它是否可以分别解析为UTF-8字符串、子消息等。 - Marc Gravell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接