在套接字上发送大型序列化对象仅在尝试增长字节数组时失败,但在使用大量字节数组时却没有问题

时间:2010-01-25 17:53:16

标签: c# sockets serialization memorystream binaryformatter

我有代码,我试图通过我的套接字接收数据时增长字节数组。这是错误的。

    public bool ReceiveObject2(ref Object objRec, ref string sErrMsg)
    {
        try
        {
            byte[] buffer = new byte[1024];
            byte[] byArrAll = new byte[0];
            bool bAllBytesRead = false;

            int iRecLoop = 0;

            // grow the byte array to match the size of the object, so we can put whatever we 
            // like through the socket as long as the object serialises and is binary formatted 
            while (!bAllBytesRead)
            {
                if (m_socClient.Receive(buffer) > 0)
                {
                    byArrAll = Combine(byArrAll, buffer);
                    iRecLoop++;
                }
                else
                {
                    m_socClient.Close();
                    bAllBytesRead = true;
                }
            }

            MemoryStream ms = new MemoryStream(buffer);
            BinaryFormatter bf1 = new BinaryFormatter();
            ms.Position = 0;
            Object obj = bf1.Deserialize(ms);
            objRec = obj;

            return true;
        }
        catch (System.Runtime.Serialization.SerializationException se)
        {
            objRec = null;
            sErrMsg += "SocketClient.ReceiveObject " + "Source " + se.Source + "Error : " + se.Message;
            return false;
        }
        catch (Exception e)
        {
            objRec = null;
            sErrMsg += "SocketClient.ReceiveObject " + "Source " + e.Source + "Error : " + e.Message;
            return false;
        }
    }

    private byte[] Combine(byte[] first, byte[] second)
    {
        byte[] ret = new byte[first.Length + second.Length];
        Buffer.BlockCopy(first, 0, ret, 0, first.Length);
        Buffer.BlockCopy(second, 0, ret, first.Length, second.Length);
        return ret;
    }    

错误:mscorlibError:输入流不是有效的二进制格式。起始内容(以字节为单位)为:68-61-73-43-68-61-6E-67-65-73-3D-22-69-6E-73-65-72 ......

然而,当我只是作弊并使用MASSIVE缓冲区大小时它很好。

        public bool ReceiveObject(ref Object objRec, ref string sErrMsg)
    {
        try
        {
            byte[] buffer = new byte[5000000];

            m_socClient.Receive(buffer);
            MemoryStream ms = new MemoryStream(buffer);
            BinaryFormatter bf1 = new BinaryFormatter();

            ms.Position = 0;
            Object obj = bf1.Deserialize(ms);
            objRec = obj;

            return true;
        }
        catch (Exception e)
        {
            objRec = null;
            sErrMsg += "SocketClient.ReceiveObject " + "Source " + e.Source + "Error : " + e.Message;
            return false;
        }
    }

这真的让我伤心。我不知道为什么它不起作用。我已经从这里提出了一个建议,所以我很确定这不是做错了吗?

我希望有人可以指出我出错的地方

2 个答案:

答案 0 :(得分:2)

Combine方法是一种非常昂贵的数组扩展方法,尤其是当MemoryStream 设计来解决这个问题时;其他回复是正确的:您必须检查读取的字节数:

using(MemoryStream ms = new MemoryStream()) {
    int bytesRead;
    while((bytesRead = m_socClient.Receive(buffer)) > 0) {
        ms.Write(buffer, 0, bytesRead);
    }
    // access ms.ToArray() or ms.GetBuffer() as desired, or
    // set Position to 0 and read
}

当然,您可以直接从流中读取 (将其传递给您的读者)

另外 - 如果您的序列化太大,您可能会考虑使用其他编码器,例如protobuf-net(尽管这会稍微改变代码)。这可能会解决一个巨大的问题。

答案 1 :(得分:1)

我对C#网络并不是很熟悉,但是每次调用Combine()并忽略从套接字读取的字节数时,是不是要向缓冲区追加1024字节?您可能至少需要一个额外的参数来表示要从second复制多少字节。