解码消息时出现反序列化异常

本文关键字:反序列化 异常 消息 解码 | 更新日期: 2023-09-27 18:01:54

我正在研究一个项目,该项目利用简单的Socket连接在客户端和服务器之间传递小变量,使用Packet.cs对象作为"旅行模式"。客户端和服务器是不同项目的一部分,但是是相同的解决方案,并且package .cs也是一个单独的"共享项目"。

这是我的package .cs文件

using System;
using System.Net;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace ConnectionData
{
    [Serializable]
    public class Packet
    {
        // these are all the different types of things we can send
        public List<string> gData;
        public string packetString;
        public int packetInt;
        public bool packetBool;
        public PacketType packetType;
        // senderID is going to be the unique GUID that we generated
        public string senderID;

        public Packet (PacketType type, string senderID)
        {
            gData = new List<String> ();
            this.senderID = senderID;
            this.packetType = type;
        }
        public Packet(byte[] packetBytes)
        {
            // deconstructs the bytes we received into packet form
            BinaryFormatter bf = new BinaryFormatter ();
            MemoryStream ms = new MemoryStream (packetBytes);
            Packet p = (Packet)bf.Deserialize (ms);
            ms.Close ();
            // assigns all the values from the packet info we received in byte form
            this.gData = p.gData;
            this.packetInt = p.packetInt;
            this.packetBool = p.packetBool;
            this.senderID = p.senderID;
            this.packetType = p.packetType;
        }
        // this converts the whole packet object into a byte array to send through the socket
        public byte[] ToBytes()
        {
            BinaryFormatter bf = new BinaryFormatter ();
            MemoryStream ms = new MemoryStream ();
            bf.Serialize (ms, this);
            byte[] bytes = ms.ToArray ();
            ms.Close ();
            return bytes;
        }
        // this function will return the active IP address of the system. if it
        // cant find one, it returns default local address
        public static string GetIP4Address()
        {
            // this lists all addresses shown in IPConfig
            IPAddress[] ips = Dns.GetHostAddresses (Dns.GetHostName ());
            foreach(IPAddress i in ips)
            {
                // if there's an IP4 address in the list, return it
                if (i.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) 
                {
                    return i.ToString ();
                }       
            }
            // else return local address
            return "127.0.0.1"; 
        }
        // enum makes it so we can define different strings, makes the packetType really easy to work with
        // allows us to define what kind of packet it is
        public enum PacketType
        {
            Registration, CloseConnection, Command
        }
    }
}

这是我用来发送数据的。当我在服务器上创建要发送到客户机的消息时,我只需调用Packet p = new Packet(Packet.PacketType.Command);socket.Send(p.ToBytes());

接收包(两个项目)使用:

public void Data_IN (object cSocket)
        {
            Socket clientSocket = (Socket)cSocket;
            byte[] buffer;
            int readBytes;
            while (Server.listening) {
                // sets our buffer array to the max size we're able to receive
                buffer = new byte[clientSocket.SendBufferSize];
                // gets the amount of bytes we've received
                readBytes = clientSocket.Receive (buffer);
                // if we actually recieve something, then sort through it
                if (readBytes > 0) {
                    // handle data
                    Packet packet = new Packet (buffer);
                    DataManager (packet); // handles the packet data
                }
            }
        }

当我尝试在第一次连接上发送注册包时,问题出现了。我启动了我的Server项目,并让它等待执行,一切工作正常。客户端能够连接,服务器发送下面创建的注册包:

Packet p = new Packet (Packet.PacketType.Registration, Server.guid);
p.packetString = HeartCore.commandKey; // commandKey is a static string variable
clientSocket.Send (p.ToBytes ());

服务器显示已成功发送,然后客户端抛出异常。耶!客户端处理数据包的接收,如上所示,使用Data_IN。异常发生在

中创建新数据包之后。
if (readBytes > 0) {
    // handle data
    Packet packet = new Packet (buffer); // this is where it stops
    DataManager (packet); // handles the packet data
}

public Packet(byte[] packetBytes)
{
    // deconstructs the bytes we received into packet form
    BinaryFormatter bf = new BinaryFormatter ();
    MemoryStream ms = new MemoryStream (packetBytes);
    Packet p = (Packet)bf.Deserialize (ms); //EXCEPTION OCCURS HERE
    ms.Close ();
    ...

如果您还记得的话,包类有一个构造函数,它接受byte[]缓冲区并将其转换为对象,然后将值从临时包对象复制到正在使用的实际对象。

抛出的异常是

System.Runtime.Serialization.SerializationException: Couldn't find assembly 'Heart' ---> System.Exception: Could not load file or assembly 'Heart' or one of its dependencies. The system cannot find the file specified.
  at System.AppDomain.Load (System.String assemblyString, System.Security.Policy.Evidence assemblySecurity, Boolean refonly) [0x00000] in <filename unknown>:0
  at System.AppDomain.Load (System.String assemblyString) [0x00000] in <filename unknown>:0
  at at (wrapper remoting-invoke-with-check) System.AppDomain:Load (string)
  at System.Reflection.Assembly.Load (System.String assemblyString) [0x00000] in <filename unknown>:0
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetDeserializationType (Int64 assemblyId, System.String className, Boolean throwOnError) [0x00000] in <filename unknown>:0
  --- End of inner exception stack trace ---
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetDeserializationType (Int64 assemblyId, System.String className, Boolean throwOnError) [0x00000] in <filename unknown>:0
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetDeserializationType (Int64 assemblyId, System.String className) [0x00000] in <filename unknown>:0
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadTypeMetadata (System.IO.BinaryReader reader, Boolean isRuntimeObject, Boolean hasTypeInfo) [0x00000] in <filename unknown>:0
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectInstance (System.IO.BinaryReader reader, Boolean isRuntimeObject, Boolean hasTypeInfo, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) [0x00000] in <filename unknown>:0
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObject (BinaryElement element, System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) [0x00000] in <filename unknown>:0
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObject (BinaryElement element, System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) [0x00000] in <filename unknown>:0
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadNextObject (BinaryElement element, System.IO.BinaryReader reader) [0x00000] in <filename unknown>:0
  at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectGraph (BinaryElement elem, System.IO.BinaryReader reader, Boolean readHeaders, System.Object& result, System.Runtime.Remoting.Messaging.Header[]& headers) [0x00000] in <filename unknown>:0
  at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.NoCheckDeserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) [0x00000] in <filename unknown>:0
  at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream) [0x00000] in <filename unknown>:0
  at ConnectionData.Packet..ctor (System.Byte[] packetBytes) [0x00016] in /home/austin/Programming/C#/Crystal-Home-Systems/ConnectionData/Packet.cs:63
  at Shard.Client.Data_IN () [0x0002f] in /home/austin/Programming/C#/Crystal-Home-Systems/Shard/Client.cs:90
  at System.Threading.Thread.StartInternal () [0x00000] in <filename unknown>:0

现在,我对c#本身有点陌生,但我有相当多的Java经验,并且以前用Java做过这种类型的服务器-客户端工作。我花了5个小时左右的时间来改变周围的东西,使用谷歌,甚至问了几个编程的朋友,我们一直无法弄清楚发生了什么。我认为Couldn't find assembly 'Heart'指的是项目Heart,它是发送导致崩溃的数据包的服务器类。

有人知道是什么原因导致了坠机吗?我开始生气了,感觉我错过了一些非常明显的东西。我试着尽可能具体,请告诉我,如果我忘记把任何东西放入问题,或者如果你需要更多的细节!

提前感谢您的帮助!

编辑:只是为了澄清,服务器和客户端能够连接没有问题,错误发生在试图解码由服务器发送给客户端的注册包时。此外,它运行在使用mono的Linux系统Kubuntu上。我不认为这有什么不同,但它可能

解码消息时出现反序列化异常

通过使用bf.Serialize (ms, this)发送数据包,您的客户端需要包含typeof(this)的程序集,即Heart程序集。然后,客户端需要该程序集对其进行反序列化。

不要序列化一个内部结构(Packet),序列化一个Payload类,你把它移到一个程序集中,并与客户端共享。

问题是这段代码:

// gets the amount of bytes we've received
readBytes = clientSocket.Receive (buffer);
// if we actually recieve something, then sort through it
if (readBytes > 0) {
    // handle data
    Packet packet = new Packet (buffer);
    DataManager (packet); // handles the packet data
}

可能在少量调用中在本地主机上工作,但是当实现任何严重的流量时,它将失败,因为buffer可能包含半个消息,或三个半消息。

你需要实现一个分帧协议来检测单独的消息。

但是当你这样做的时候,你似乎是从头开始重新创建协议缓冲区。

我找到了解决问题的办法。cs文件位于一个共享项目中。据我所知,共享项目使用解决方案中所有其他项目的资源,这不是我想要做的。

我尝试了各种各样的方法,包括CodeCaster给出的惊人答案,但都不起作用。

为了解决这个异常,我将package .cs文件重制为共享库项目,而不是共享项目。这允许将package .cs文件作为.dll文件放入构建路径中,使其不具有来自其他项目的资源。

解决方案构建和执行完美!我希望这对将来的人有所帮助!