protobuf-csharp 端口

Posted

技术标签:

【中文标题】protobuf-csharp 端口【英文标题】:protobuf-csharp-port 【发布时间】:2010-08-27 15:12:35 【问题描述】:

我正在使用 Jon Skeet 的(优秀的)将 Google 协议缓冲区移植到 C#/.Net。

为了练习,我编写了一个虚拟即时通讯应用程序,它通过套接字发送一些消息。我有一个消息定义如下:-

message InstantMessage <br/>
  required string Message = 1;<br/>
  required int64 TimeStampTicks = 2; <br/>

当发送者序列化消息时,它发送的非常优雅:-

        ...
        InstantMessage.Builder imBuild = new InstantMessage.Builder();

        imBuild.Message = txtEnterText.Text;
        imBuild.TimeStampTicks = DateTime.Now.Ticks;

        InstantMessage im = imBuild.BuildPartial();

        im.WriteTo(networkStream);
        ...

这很好用。但另一方面,我无法让ParseFrom 工作。

我想使用:-

InstantMessage im = InstantMessage.ParseFrom(networkStream);

但是我不得不将它读取到字节,然后从这里解析它。由于多种原因,这显然不是理想的。当前代码是:-

while (true)
        
            Byte[] byteArray = new Byte[10000000];

            int intMsgLength;
            int runningMsgLength = 0;

            DateTime start = DateTime.Now;

            while (true)
            
                runningMsgLength += networkStream.Read(byteArray, runningMsgLength, 10000000 - runningMsgLength);

                if (!networkStream.DataAvailable)
                    break;

            

            InstantMessage im = InstantMessage.ParseFrom(byteArray.Take(runningMsgLength).ToArray());

当我尝试使用ParseFrom 时,即使我知道在线上有有效的 GB 消息,控制也不会返回到调用方法。

如有任何建议,我们将不胜感激,

私服

【问题讨论】:

Dataavailable 在这里是一个糟糕的选择,顺便说一句。它不会告诉您任何有关实际数据的信息。 明天会调查这个。今晚太累了。 【参考方案1】:

很抱歉花点时间来回答这个问题。正如 Marc 所说,协议缓冲区没有终止符,除非它们是嵌套的,否则它们没有长度前缀。但是,您可以自己添加长度前缀。如果您查看 MessageStreamIterator 和 MessageStreamWriter,您会看到我是如何做到这一点的 - 基本上我假装我在消息中间,将嵌套消息写为字段 1。不幸的是,当阅读消息,我必须使用内部详细信息 (BuildImpl)。

现在有另一个 API 可以执行此操作:IMessage.WriteDelimitedToIBuilder.MergeDelimitedFrom。这可能是您目前想要的,但我似乎记得在检测流结束方面存在一个小问题(即当没有其他消息要读取时)。我不记得目前是否有修复它 - 我感觉它在 Java 版本中发生了变化,我可能还没有移植这个变化。无论如何,这绝对是值得关注的领域。

【讨论】:

乔恩,对于迟到的回复深表歉意 - 我一直在参加培训课程。谢谢你的提示——我看了一眼,我相信通过这个解释我可以弄清楚。再次感谢,我真的很感激。私服【参考方案2】:

Protobuf 没有终止符 - 所以要么关闭流,要么使用您自己的长度前缀等。Protobuf-net 通过 SerializeWithLenghtPrefix / DeserializeWithLengthPrefix 轻松公开这一点。

简单地说:没有这个,它就无法知道每条消息在哪里结束,所以一直尝试读取到流的末尾。

【讨论】:

谢谢 Marc,我不清楚您在哪里看到 SerializeWithLengthPrefix 及其相应的 Derserialize...您是说我需要在执行操作之前调用 InstantMessage 对象上的方法:im.WriteTo(networkStream ); ?再次感谢 @phil - protobuf-net 是一个不同的实现,但同样的方法应该可以工作。在 Jon 的版本中可能存在一个现有方法:我不确定。

以上是关于protobuf-csharp 端口的主要内容,如果未能解决你的问题,请参考以下文章

了解gRPC一篇就够了

Jmeter protobuf 测试。无法读取 Protobuf 消息

.Net 协议缓冲区到 JSON,JsonFormatReader 类不处理最外面的花括号?

基于nginx实现protobuf RPC

服务器更改时如何为客户端更新 protobuf 文件

尴尬的事情又发生Newtonsoft.Json vs Protobuf.net