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

Posted

技术标签:

【中文标题】C# Protobuf-net:如何从网络流中连续反序列化?【英文标题】:C# Protobuf-net: how do I deserialize consecutively from a network stream? 【发布时间】:2015-06-03 23:38:05 【问题描述】:

我(感激地)使用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# 网络流没有可供我比较的 Length 属性。

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

我在这里错过了什么?

【问题讨论】:

【参考方案1】:

鉴于我正在使用“TryDeserializeWithLengthPrefix”,我曾期望库能够整理等待流以有足够的数据来解析整个对象。

没有可靠有效的方法来“解决”抽象 Stream 对象的等待问题。

C# 网络流没有可供我比较的 Length 属性。

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

【讨论】:

这似乎是一个高效的解决方案,谢谢。我将推迟将其标记为已接受的答案,直到我们收到作者的来信或一段时间过去了。与此同时,我会实现这个:)

以上是关于C# Protobuf-net:如何从网络流中连续反序列化?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 protobuf-net 读回附加的对象?

如何在 C# 中从内存流中播放 MP3?

使用 IPC C# 时如何有效地从管道流中读取

如何使用 protobuf-net 处理 .proto 文件

尽快在网络流中搜索块

连续从流中读取?