代码之家  ›  专栏  ›  技术社区  ›  Kiril

令人沮丧的TCP序列化异常:二进制流“0”不包含有效的BinaryHeader

  •  1
  • Kiril  · 技术社区  · 14 年前

    我在网上发了一个问题 how to send large objects over TCP 看来首要问题解决了,但现在 我还有一个例外:

    二进制流“0”不包含 有效的二进制头。可能的原因 流或对象版本无效 在序列化和 反序列化。

    public Message Receive()
    {
        if (_tcpClient == null || !_tcpClient.Connected)
        {
            throw new TransportException("Client Not Connected");
        }
    
        // buffers
        byte[] msgBuffer;
        byte[] sizeBuffer = new byte[sizeof(int)];
    
        // bites read
        int readSize = 0;
        // message size
        int size = 0;
    
        MemoryStream memStream = new MemoryStream();
        NetworkStream netStream = _tcpClient.GetStream();
        BinaryFormatter formatter = new BinaryFormatter();
        try
        {
            // Read the message length
            netStream.Read(sizeBuffer, 0, sizeof(int));
    
            // Extract the message length
            size = BitConverter.ToInt32(sizeBuffer, 0);
            msgBuffer = new byte[size];
    
            // Fill up the message msgBuffer
            do
            {
                // Clear the buffer
                Array.Clear(msgBuffer, 0, size);
    
                // Read the message
                readSize += netStream.Read(msgBuffer, 0, _tcpClient.ReceiveBufferSize);
    
                // Write the msgBuffer to the memory streamvb
                memStream.Write(msgBuffer, 0, readSize);
    
            } while (readSize < size);
    
            // Reset the memory stream position
            memStream.Position = 0;
    
            // Deserialize the message
            return (Message)formatter.Deserialize(memStream); // <-- Exception here
    
        }
        catch (System.Exception e)
        {
            if (_tcpClient == null || !_tcpClient.Connected)
            {
                throw new TransportException("Client Not Connected");
            }
            else
            {
                throw e;
            }
        }
    }
    

    与此示例相关的其余代码可以在我的 original question .

    更新

    Read 最多读取 _tcpClient.ReceiveBufferSize 一次读取一个字节,而不是试图读取完整的消息大小(可以大于缓冲区大小),虽然异常的频率略有下降,但仍然经常发生。

    2 回复  |  直到 4 年前
        1
  •  3
  •   Darin Dimitrov    14 年前

    我建议您稍微简化一下代码:

    public Message Receive()
    {
        try
        {
            if (_tcpClient == null || !_tcpClient.Connected)
            {
                throw new TransportException("Client Not Connected");
            }
    
            using (var stream = _tcpClient.GetStream())
            using (var reader = new BinaryReader(stream))
            {
                int size = reader.ReadInt32();
                byte[] buffer = reader.ReadBytes(size);
                using (var memStream = new MemoryStream(buffer))
                {
                    var formatter = new BinaryFormatter();
                    return (Message)formatter.Deserialize(memStream);
                }
            }
        }
        catch (System.Exception e)
        {
            if (_tcpClient == null || !_tcpClient.Connected)
            {
                throw new TransportException("Client Not Connected");
            }
            throw e;
        }
    }
    

    此外,如果你这样做是为了好玩和/或教育的目的,那么这是没关系的,但在一个实际的项目中,你可能应该考虑WCF,以便通过有线传输对象。

        2
  •  0
  •   alerya    13 年前