使用 protobuf CodedInputStream 从 byte[] 读取

Fan*_*Fox 6 c# protocol-buffers

在下面的代码中,我想在 C# 中使用预定义的 protobuf 消息。我发现我能够编写并使用该方法来获取已创建的方法并制作byte[]

 ContainerMessage containerMessage = new ContainerMessage();
 containerMessage.Type = CommandType.Connect;
 containerMessage.Connect = new Connect();
 containerMessage.Connect.ClientName = "TemporaryClientName";

 byte[] stream = new byte[containerMessage.CalculateSize()];   
 using (Google.Protobuf.CodedOutputStream outstream = new Google.Protobuf.CodedOutputStream(stream))
 {
     containerMessage.WriteTo(outstream);
 }
Run Code Online (Sandbox Code Playgroud)

这按预期工作,我可以检查消息,并且值与预期的一样byte[]。但是,如果我尝试反序列化,即使是byte[]我刚刚创建的这个简单的:

  using (Google.Protobuf.CodedInputStream instream = new Google.Protobuf.CodedInputStream(stream))
  {
      instream.ReadMessage(containerMessage);
  }
Run Code Online (Sandbox Code Playgroud)

它失败了:

Google.Protobuf.dll 中发生“Google.Protobuf.InvalidProtocolBufferException”类型的未处理异常

附加信息:协议消息包含无效标签(零)。

这是从byte[]正确的 protobuf 反序列化的方式吗?


Protobuf 的定义是:

message ContainerMessage {
    CommandType type = 1;
    bool commandSuccess = 2;

    oneof message {
        Connect connect = 3;
    }
}

enum CommandType {
    START = 0;
    CONNECT = 2;
}

message Connect {
    string ClientName = 1;
    uint32 PushPullPort = 2;
}
Run Code Online (Sandbox Code Playgroud)

CS文件是用命令行生成的:

protoc.exe -I=%CD% --csharp_out=..\GeneratedCsMessaging\ Connect.proto
Run Code Online (Sandbox Code Playgroud)

Tor*_*ung 7

和主要供编译的原型类使用CodedOutputStreamCodedOutputStream 的 API声明了这一点,并提到如果您希望手动编写的代码调用这两个类中的任何一个,则需要在每个值之前使用它们的方法。CodedInputStreamWriteTag

但是,由于您想使用 Google Protobuf 进行序列化和解析任何 System.IO.Stream 都会按照预期完成这项工作。C# Protocol Buffer 基础知识的解析和序列化部分对此进行了详细记录和描述。在 Google Protobuf 的 Github 中可以找到的示例对于快速掌握 Google Protobuf 的窍门非常有帮助。在那里您可以看到 a用于序列化对象,而该方法可用于从序列化数据中解析对象。MemoryStreamParse.ParseFrom

正如您在问题评论中提到的,using Google.Protobuf;这是使用 Google Protobuf 功能的重要组成部分。

编辑:您的案例中的示例用法可能如下所示

        byte[] serializedBytes;

        ContainerMessage containerMessage = new ContainerMessage()
        {
            Connect = new Connect()
            {
                ClientName = "TemporaryClientName",
            },
            Type = CommandType.Connect,
        };

        using( MemoryStream stream = new MemoryStream())
        {
            containerMessage.WriteTo(stream);
            serializedBytes = stream.ToArray();
        }

        ContainerMessage parsedCopy = ContainerMessage.Parser.ParseFrom(serializedBytes);
Run Code Online (Sandbox Code Playgroud)