C# BinaryFormatter反序列化有时会引发异常

C# BinaryFormatter反序列化有时会引发异常,c#,serialization,C#,Serialization,我有一个客户端和服务器端应用程序的项目。当然,他们交换数据。我在大型对象(约5 mb)上测试数据流时遇到了一个问题: 有时BinaryFormatter反序列化()会引发以下异常: 二进制流“0”不包含有效的BinaryHeader。可能的原因是序列化和反序列化之间的无效流或对象版本更改。--(不一定是流“0”,但也可能是其他索引)。我检查了数据的大小(发送端和接收端),它们是相同的,但内容(字节的平均顺序与发送的数据包不同)。 下面是代码: public static ICommand De

我有一个客户端和服务器端应用程序的项目。当然,他们交换数据。我在大型对象(约5 mb)上测试数据流时遇到了一个问题: 有时BinaryFormatter反序列化()会引发以下异常:

二进制流“0”不包含有效的BinaryHeader。可能的原因是序列化和反序列化之间的无效流或对象版本更改。--(不一定是流“0”,但也可能是其他索引)。我检查了数据的大小(发送端和接收端),它们是相同的,但内容(字节的平均顺序与发送的数据包不同)。 下面是代码:

 public static ICommand Deserialize(byte[] bytes)
    {


        BinaryFormatter frmt=new BinaryFormatter();
        frmt.AssemblyFormat = FormatterAssemblyStyle.Simple;
        frmt.Binder=new BindingType();
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            ms.Seek(0, SeekOrigin.Begin);
            return (ICommand)frmt.Deserialize(ms);
        }
    }

    private class BindingType:SerializationBinder//for deserializeing object in     assembly, different from where serialized
    {
        public override Type BindToType(string assemblyName, string typeName)
        {
            Type toDeserialize = null;
            String exeAssembly = Assembly.GetExecutingAssembly().FullName;
            if (typeName == "Server.ServerPlayer")
                typeName = "Command_Entities.Player";
            if (typeName == "Server.ServerLobby")
                typeName = "Command_Entities.Lobby";


            // The following line of code returns the type.
            toDeserialize = Type.GetType(String.Format("{0}, {1}",typeName, exeAssembly));//change assembly name and type accordingly to object being deserialized
            //to match current assembly name

            return toDeserialize;
        }
    }
这是我的接收逻辑:

 private void AsyncReceiveLoop(object obj)
    {
        byte[] metaData = new byte[4];
        byte[] data = null;
        int received = 0;
        try
        {
            while (!_stop)
            {
                _me.Receive(metaData, 0, 4, SocketFlags.None);
                _packetSize =Convert.ToInt32( BitConverter.ToUInt32(metaData, 0));
                data = CorrectReceiver.Receive(_me, _packetSize).ToArray();


                if (_packetSize == data.Length)
                {
                    _mainCallback(data);
                }

            }

        }
        catch (SocketException ex)
        {
            _ecxeptionCallback(ex);
        }

    }
  public static byte[] Receive(Socket soc, int packetSize)
    {

        NetworkStream ns=new NetworkStream(soc,false);
        List<byte> totalBytes=new List<byte>();
        int receivedTotal = 0;
        byte[] tempBytes=null;
        int size = 0;
        int received = 0;
        int available = 0;
        byte[] rec = null;
        tempBytes = new byte[packetSize];
        while (packetSize > receivedTotal)
        {

            if (ns.DataAvailable)
            {



                received=ns.Read(tempBytes, receivedTotal, packetSize-receivedTotal);
                if(received==0)
                    throw new Exception("Connection closed...");//connection closed when 0 bytes received

                receivedTotal += received;


            }
            else{ System.Threading.Thread.Sleep(50);}

        }
        return tempBytes;
    }
这一个(正确的接收者):

 private void AsyncReceiveLoop(object obj)
    {
        byte[] metaData = new byte[4];
        byte[] data = null;
        int received = 0;
        try
        {
            while (!_stop)
            {
                _me.Receive(metaData, 0, 4, SocketFlags.None);
                _packetSize =Convert.ToInt32( BitConverter.ToUInt32(metaData, 0));
                data = CorrectReceiver.Receive(_me, _packetSize).ToArray();


                if (_packetSize == data.Length)
                {
                    _mainCallback(data);
                }

            }

        }
        catch (SocketException ex)
        {
            _ecxeptionCallback(ex);
        }

    }
  public static byte[] Receive(Socket soc, int packetSize)
    {

        NetworkStream ns=new NetworkStream(soc,false);
        List<byte> totalBytes=new List<byte>();
        int receivedTotal = 0;
        byte[] tempBytes=null;
        int size = 0;
        int received = 0;
        int available = 0;
        byte[] rec = null;
        tempBytes = new byte[packetSize];
        while (packetSize > receivedTotal)
        {

            if (ns.DataAvailable)
            {



                received=ns.Read(tempBytes, receivedTotal, packetSize-receivedTotal);
                if(received==0)
                    throw new Exception("Connection closed...");//connection closed when 0 bytes received

                receivedTotal += received;


            }
            else{ System.Threading.Thread.Sleep(50);}

        }
        return tempBytes;
    }
公共静态字节[]接收(Socket soc,int packetSize)
{
NetworkStream ns=新的NetworkStream(soc,false);
List totalBytes=新列表();
int receivedTotal=0;
byte[]tempBytes=null;
int size=0;
接收到的int=0;
int available=0;
字节[]rec=null;
tempBytes=新字节[packetSize];
while(packetSize>receivedTotal)
{
如果(可用的ns.数据)
{
received=ns.Read(tempBytes、receivedTotal、packetSize receivedTotal);
如果(接收==0)
抛出新异常(“连接已关闭…”);//接收到0字节时连接已关闭
receivedTotal+=已接收;
}
else{System.Threading.Thread.Sleep(50);}
}
返回tempBytes;
}
您可能会在这里找到一些不必要或愚蠢的解决方案,但这个问题持续了很长时间,我在代码和逻辑上做了很多更改。
所以,如果你们中的任何人在这里看到了什么,这可能是问题的原因,或者如果过去有人遇到过这个问题,请帮助我找到这个bug。

我解决了这个问题,问题在于线程:我在AsyncReceiveLoop中切换线程,得到了这个奇怪的bug。在切换之间的某个点上,旧线程正在读取字节,而新线程在读取被截断的字节之后。应始终小心交叉穿线。谢谢

你说有时候字节的顺序不对?如果是这样,那么您没有反序列化问题,而是通信问题。可能是读取长度时,没有接收到4个字节。如果发生这种情况,那么您收到的数据包的第一部分将是长度报头的一部分。您可能应该检查以确保在读取数据包大小时实际得到4个字节。嗨,Jim。谢谢你的回复。我解决了这个问题,问题出在线程方面:我在AsyncReceiveLoop中切换线程,发现了这个奇怪的错误。在切换之间的某个点上,旧线程正在读取字节,而新线程在读取被截断的字节之后。应始终小心交叉穿线。谢谢。@GiorgiEgoTwinKhutsishvili如果你解决了你的问题,你应该将你的解决方案作为答案发布,然后接受它。