C#Protobuf-net:如何从网络流中连续反序列化?

时间:2015-06-03 23:38:05

标签: c# deserialization protobuf-net networkstream

我(感激地)使用Marc Gravell优秀的Protobuf-net Protocol Buffers库。不幸的是,我是愚蠢的,并且无法理解反序列化通过电线进入的对象的正确方法。

作为我努力的基础,我遵循这些问题的建议:

Issue deserializing (protocolBuffer) serialized data using protobuf-net
protobuf: consecutive serialize and deserialize to/from socket

我正在为整个会话(几分钟......几小时......谁知道?)打开一个TCP连接,并使用一个网络流,只要连接存在就会持续存在。我通过这个流接收了很多PB消息。

鉴于我正在使用“TryDeserializeWithLengthPrefix”,我原本期望该库在流上等待有足够的数据来解析整个对象。但事实并非如此。

我写了一个简单的测试:

    [Test]
    public void DeserializeSimpleObjectInParts ()
    {
        SimpleObject origin = new SimpleObject();
        byte[] wholeObj = ProtobufSerializer.SerializeToByteArray ( origin );
        int length = wholeObj.Length;
        int midpoint = length / 2;
        int sizeA = midpoint;
        int sizeB = length - midpoint;
        byte[] aaa = new byte[sizeA];
        byte[] bbb = new byte[sizeB];
        for ( int i = 0; i < midpoint; i++ )
        {
            aaa [ i ] = wholeObj [ i ];
        }
        for ( int j = midpoint; j < length; j++ )
        {
            bbb [ j - midpoint ] = wholeObj [ j ];
        }

        using ( MemoryStream streamA = new MemoryStream ( aaa ) )
        {
            using ( MemoryStream streamB = new MemoryStream ( bbb ) )
            {
                streamA.Position = 0;
                streamB.Position = 0;
                Debug.LogDebug ( "streamA.Length = " + streamA.Length + ", streamB.Length = " + streamB.Length );

                object resultA = null;
                bool succeededA = false;
                try {
                    succeededA = ProtobufSerializer.Deserialize ( streamA, out resultA );
                }
                catch ( Exception e )
                {
                    Debug.LogDebug ( "Exception = " + e );
                    Debug.LogDebug ( "streamA.Position = " + streamA.Position + ", streamA.Length = " + streamA.Length );
                }
            }
        }
    }

请注意,在上面,“ProtobufSerializer.Deserialize”只是通过我自己的服务类直接调用“TryDeserializeWithLengthPrefix”。类型编码业务就在那里。

当我运行此测试时,抛出以下异常:

System.IO.EndOfStreamException: Failed to read past end of stream.

This advice from our friends at Google表明我有责任查看套接字代码中的长度前缀。但这有什么帮助呢? C#网络流没有长度属性供我比较。

我真的必须做一个在流上运行循环的中间步骤,构建正确大小的字节数组,然后从它们创建新流,我将其传递给Protobuf-net?这似乎是反模式和性能打击。

我在这里缺少什么?

1 个答案:

答案 0 :(得分:2)

  

鉴于我正在使用“TryDeserializeWithLengthPrefix”,我原本期望该库在流上等待有足够的数据来解析整个对象。

没有可靠而有效的方法在抽象的Stream对象上“理清”等等。

  

C#网络流没有我可以比较的长度属性。

将您从套接字流写入的数据计数到缓冲区流。那将是你的“长度”属性,与你在开头得到的长度前缀进行比较。一旦有足够的数据,请寻找缓冲流回到前缀并将其传递给反序列化器以获取对象。现在再次寻找缓冲流并重新使用它来获取下一条消息。重复。