C# C二进制格式化程序序列化和反序列化-3个随机异常

C# C二进制格式化程序序列化和反序列化-3个随机异常,c#,serialization,deserialization,C#,Serialization,Deserialization,我正在创建一个C应用程序客户端和服务器。它们是独立的项目,都引用一个DLL,该DLL可以序列化和反序列化输入到它们中的任何对象 一切正常,直到我开始使用实时桌面监控视频。DLL包含一个自定义屏幕截图类,该类接收位图并将其写入该类的公共memorystream。以下是如何完成这一切: 客户端按钮将整个屏幕截图作为位图 客户端构造一个屏幕截图对象,将其序列化,并将其发送到服务器。序列化它会将其转换为字节客户端,然后重复这些步骤以不断发送屏幕截图 服务器接收这些字节,对其进行反序列化,检查它是否为屏幕

我正在创建一个C应用程序客户端和服务器。它们是独立的项目,都引用一个DLL,该DLL可以序列化和反序列化输入到它们中的任何对象

一切正常,直到我开始使用实时桌面监控视频。DLL包含一个自定义屏幕截图类,该类接收位图并将其写入该类的公共memorystream。以下是如何完成这一切:

客户端按钮将整个屏幕截图作为位图 客户端构造一个屏幕截图对象,将其序列化,并将其发送到服务器。序列化它会将其转换为字节客户端,然后重复这些步骤以不断发送屏幕截图 服务器接收这些字节,对其进行反序列化,检查它是否为屏幕截图类型,然后引发事件&如果为true,则在表单上显示此图像。 是的,我确实收到了一个实时图像提要,它会显示在表单上,但这只能工作3到10秒。我总共得到3个例外,它们是从客户机中随机出现的

我也会发布一些关于它们的细节截图,请原谅奇怪的异常处理程序框。

以下是DLL中的序列化和反序列化代码:

    public static byte[] Serialize(Object paramObj)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, paramObj);
            return ms.ToArray();
        }
    }
    public static Object Deserialize(byte[] paramBuffer)
    {
        using (MemoryStream ms = new MemoryStream(paramBuffer))
        {
            BinaryFormatter bf = new BinaryFormatter();
            //ms.Position = 0;
            ms.Seek(0, SeekOrigin.Begin);
            return (Object)bf.Deserialize(ms);
        }
    }
我花了好几个小时研究这些错误,却什么也没发现,我似乎应用的任何东西都会产生另一个错误

感谢您花时间分析我的混乱代码。真的很奇怪

如果您对服务器如何处理接收到的数据感到好奇:

    public void receiveAll()
    {
        byte[] _buffer = new byte[55000];

        _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), _clientSocket);

        void ReceiveCallback(IAsyncResult AR)
        {
            try
            {
                _clientSocket = (Socket)AR.AsyncState;
                int received = _clientSocket.EndReceive(AR);
                byte[] receivedbuffer = new byte[received];
                Array.Copy(_buffer, receivedbuffer, received);

                // The "ObjectHandler" is the class to Ser & Deser in the DLL
                Object data = ObjectHandler.Deserialize(receivedbuffer);

                try 
                {
                    // Check the data that is received & determine type
                }
                catch (Exception ex)
                {
                     // Show Exception box
                }

                // Repeat the receive process...
                _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), _clientSocket);
            }
            catch (Exception ex)
            {
                RemoveClient();
                // Show Exception box
            }
        }
    }

序列化异常仅仅意味着数据不完整或损坏。问题在于数据传输,而不是序列化

我假设您正在使用TCP套接字进行连接?不能保证套接字或TcpClient、流等上的读取调用一次提供您期望的所有数据。缓冲区由接收端当前可用的数据中的最大字节数填充。特别是在通过网络发送大量数据时,它可能以多个部分数据包而不是全部数据包的形式到达。此外,单个接收呼叫可能同时返回当前消息的结尾和下一条消息的开头


您需要在一个循环中反复调用BeginReceive,直到您知道您有完整的消息,例如,通过在发送端手动为传输的数据添加长度值前缀,然后等待,直到您在接收端缓冲了至少该数量的数据。

如果传输的数据只是序列化一个对象,我如何能够将传输的数据与自身的长度连接起来?这让我更加困惑服务器如何在没有反序列化的情况下确定该长度。。。但我确实理解你的意思&这让我头脑更清醒了。我只是需要实现它,你知道序列化数据在写入发送端的MemoryStream后需要多长时间。您可以在发送数据之前发送该值。