[英]Deserialization Exception when decoding a message
我正在一个项目中,该项目利用Packet.cs对象作为“行进模式”,利用简单的Socket连接在客户端和服务器之间传递小变量。 客户端和服务器是不同项目的一部分,但是是相同的解决方案,而Packet.cs也是一个单独的“共享项目”。
这是我的packet.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
}
}
}
当我尝试在第一个连接上发送注册数据包时,就会出现问题。 我启动我的服务器项目,让它仅在等待时执行,一切正常。 客户端可以连接,服务器发送在此处创建的注册数据包:
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 []缓冲区并将其转换为对象,然后将值从temp数据包对象复制到正在使用的实际对象。
抛出的异常是
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有相当的经验,并且以前已经使用过这种类型的服务器-客户端工作。 在过去的5个小时左右的时间里,我一直在使用Google进行更改,甚至询问几个编程朋友,但我们一直无法弄清发生了什么。 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
}
可能会在少量调用中在localhost上工作,但是当实现任何严重流量时,它将失败,因为buffer
可能包含一半消息或三条消息。
您需要实现成帧协议以检测单独的消息。
我找到了解决我问题的方法。 Packet.cs文件位于共享项目中。 据我所知,共享项目使用解决方案中所有其他项目的资源,这不是我想要做的。
我尝试了各种方法,包括CodeCaster给出的惊人答案,但是没有任何效果。
为了解决该异常,我将Packet.cs文件重新制作为共享库项目,而不是共享项目。 这样就可以将Packet.cs文件作为.dll文件放入构建路径,从而使其不具有其他项目的资源。
解决方案的构建和执行完美! 希望这对以后的人有所帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.