我正在使用Jon Skeet的(出色的)Google的Protocol Buffers移植到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消息,控制也不会返回到调用方法。
我们将非常感谢您的建议,
PW
发布于 2010-08-30 16:41:41
很抱歉花了一段时间来回答这个问题。正如Marc所说,协议缓冲区没有终止符,除非它们是嵌套的,否则它们不会有长度前缀。但是,您可以自己添加长度前缀。如果你看看MessageStreamIterator和MessageStreamWriter,你就会明白我是如何做到这一点的--基本上,我假装我在一条消息的中间,将一个嵌套的消息写成字段1。不幸的是,在读取消息时,我不得不使用内部细节(BuildImpl)。
现在有另一个API可以做到这一点:IMessage.WriteDelimitedTo和IBuilder.MergeDelimitedFrom。这可能是你现在想要的,但我记得它在检测流的结尾方面有一个小问题(即当没有另一条消息可读时)。我不记得目前是否有修复--我有一种感觉,它在Java版本中已经改变了,我可能还没有移植这个改变。无论如何,这绝对是值得关注的领域。
发布于 2010-08-27 23:58:33
Protobuf没有终止符-所以要么关闭流,要么使用自己的长度前缀等。Protobuf-net很容易通过SerializeWithLenghtPrefix / DeserializeWithLengthPrefix公开这一点。
简单地说:如果没有这个,它就不能知道每个消息在哪里结束,所以一直尝试读到流的末尾。
https://stackoverflow.com/questions/3585562
复制相似问题