protobuf的-CSHARP端口

时间:2010-08-27 15:12:36

标签: c# .net networkstream protocol-buffers

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

在练习中,我编写了一个虚拟的Instant Messenger应用程序,它可以在套接字上发送一些消息。我的消息定义如下: -

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消息在线上,控制也不会返回到调用方法。

非常感谢任何建议,

PW

2 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:0)

Protobuf没有终止符 - 所以要么关闭流,要么使用你自己的长度前缀等.Protobuf-net通过SerializeWithLenghtPrefix / DeserializeWithLengthPrefix轻松暴露这个。

简单地说:没有它,它无法知道每条消息的结束位置,所以一直试着读到流的末尾。