我正在使用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
答案 0 :(得分:4)
很抱歉花点时间回答这个问题。正如Marc所说,协议缓冲区没有终结符,除非它们是嵌套的,否则它们不是长度前缀。但是,您可以自己加上长度前缀。如果你看一下MessageStreamIterator和MessageStreamWriter,你会看到我是怎么做的 - 基本上我假装我正处于一条消息的中间,把一个嵌套的消息写成字段1.不幸的是,在阅读时消息,我必须使用内部细节(BuildImpl)。
现在有另外一个API可以执行此操作:IMessage.WriteDelimitedTo
和IBuilder.MergeDelimitedFrom
。这可能是你现在想要的,但我似乎记得在检测流的结束方面(即没有另一条消息要读)时,它有一个小问题。我不记得目前是否有一个修复程序 - 我感觉它在Java版本中已经改变了,我可能还没有移植过这个改变。无论如何,这绝对是值得关注的领域。
答案 1 :(得分:0)
Protobuf没有终止符 - 所以要么关闭流,要么使用你自己的长度前缀等.Protobuf-net通过SerializeWithLenghtPrefix / DeserializeWithLengthPrefix轻松暴露这个。
简单地说:没有它,它无法知道每条消息的结束位置,所以一直试着读到流的末尾。