通过网络发送自定义结构-SerializationException
本文关键字:自定义 结构 -SerializationException 网络 | 更新日期: 2023-09-27 17:57:50
早上,我有一个TCP服务器和一个TCP客户端。这是服务器的代码:
public static class Server
{
private static IPEndPoint endPoint;
private static TcpListener tcpServer;
private static List<Client> clients;
private static Thread threadListen;
private static ASCIIEncoding encoding;
public static void Initialize(IPAddress allowedIPAddress, int port)
{
endPoint = new IPEndPoint(allowedIPAddress, port);
tcpServer = new TcpListener(endPoint);
clients = new List<Client>();
threadListen = new Thread(new ThreadStart(Listen));
encoding = new ASCIIEncoding();
}
public static void Start()
{
threadListen.Start();
}
public static byte[] PacketToArray(Packet packet)
{
IFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, packet);
byte[] packetArray = stream.GetBuffer();
stream.Close();
return packetArray;
}
public static Packet ArrayToPacket(byte[] array)
{
IFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream(array);
Packet packet = new Packet();
packet = (Packet) formatter.Deserialize(stream);
stream.Close();
return packet;
}
public static void Send(Client target, Packet packet)
{
byte[] packetArray = PacketToArray(packet);
target.networkStream.Write(packetArray, 0, packetArray.Length);
target.networkStream.Flush();
OnSend(packet);
}
private static void Listen()
{
tcpServer.Start();
while (true)
{
try
{
Client client = new Client();
client.tcpClient = tcpServer.AcceptTcpClient();
client.networkStream = client.tcpClient.GetStream();
client.thread = new Thread(new ParameterizedThreadStart(HandleCommunication));
clients.Add(client);
client.thread.Start(client);
OnJoin(client);
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
break;
}
}
}
private static void HandleCommunication(object client)
{
Client handleClient = (Client) client;
byte[] messageBuffer = new byte[4096];
int bytesRead = 0;
while (true)
{
bytesRead = 0;
try
{
bytesRead = handleClient.networkStream.Read(messageBuffer, 0, messageBuffer.Length);
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
break;
}
if (bytesRead == 0)
{
clients.Remove(handleClient);
OnLeave(handleClient);
break;
}
Packet packet = ArrayToPacket(messageBuffer);
OnReceive(packet);
}
}
private static void OnStart()
{
Console.WriteLine("Server started on port .");
}
private static void OnJoin(Client client)
{
Console.WriteLine("Client [ID] connected.");
Send(client, PacketGenerator.Generate(OpCodes.opHandshake, null));
}
private static void OnLeave(Client client)
{
Console.WriteLine("Client [ID] disconnected.");
}
private static void OnSend(Packet packet)
{
Console.WriteLine("Server: " + packet.opcode.ToString() + " | " + packet.message);
}
private static void OnReceive(Packet packet)
{
Console.WriteLine("Client [ID]: " + packet.opcode.ToString() + " | " + packet.message);
}
public struct Client
{
public TcpClient tcpClient;
public NetworkStream networkStream;
public Thread thread;
}
}
这是客户端的代码:
[Serializable]
public struct Packet
{
public int opcode;
public string message;
}
public static class Client
{
private static IPEndPoint endPoint;
private static TcpClient tcpClient;
private static NetworkStream networkStream;
private static Thread threadCommunication;
private static ASCIIEncoding encoding;
public static void Initialize(string ipAddress, int port)
{
endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
tcpClient = new TcpClient();
networkStream = null;
threadCommunication = new Thread(new ThreadStart(HandleCommunication));
encoding = new ASCIIEncoding();
}
public static void Connect()
{
tcpClient.Connect(endPoint);
threadCommunication.Start();
Console.WriteLine("Connected to server.");
networkStream = tcpClient.GetStream();
}
public static byte[] PacketToArray(Packet packet)
{
IFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, packet);
byte[] packetArray = stream.GetBuffer();
stream.Close();
return packetArray;
}
public static Packet ArrayToPacket(byte[] array)
{
IFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream(array);
Packet packet = new Packet();
packet = (Packet)formatter.Deserialize(stream);
stream.Close();
return packet;
}
public static void Send(Packet packet)
{
byte[] packetArray = PacketToArray(packet);
networkStream.Write(packetArray, 0, packetArray.Length);
networkStream.Flush();
OnSend(packet);
}
private static void HandleCommunication()
{
byte[] messageBuffer = new byte[4096];
int bytesRead = 0;
while (true)
{
bytesRead = 0;
try
{
bytesRead = networkStream.Read(messageBuffer, 0, messageBuffer.Length);
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
break;
}
if (bytesRead == 0)
{
Console.WriteLine("Connection closed.");
break;
}
Packet packet = ArrayToPacket(messageBuffer);
OnReceive(packet);
}
}
private static void OnSend(Packet packet)
{
Console.WriteLine("Client [ID]: " + packet.opcode.ToString() + " | " + packet.message);
}
private static void OnReceive(Packet packet)
{
Console.WriteLine("Server: " + packet.opcode.ToString() + " | " + packet.message);
switch (packet.opcode)
{
case OpCodes.opHandshake:
Send(PacketGenerator.Generate(OpCodes.opHandshake, null));
break;
}
}
}
但是,当我从服务器向客户端发送数据包(握手)时,客户端在"packet=(packet)formatter.Deserialize(stream);"确切的消息是:找不到程序集"ComDee,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"。(ComDee是运行服务器的程序集)。
为什么?客户端的数据包结构与服务器的结构相同。
更新
我已经编辑了Server和Client类,并使用了protobuf-net。但是客户端类中的"OnReceive"不会被调用。问题出在哪里?服务器类别:
[ProtoContract]
public struct Packet
{
[ProtoMember(1)] public int opcode;
[ProtoMember(2)] public string message;
}
public static class Server
{
private static IPEndPoint endPoint;
private static TcpListener tcpServer;
private static List<Client> clients;
private static Thread threadListen;
private static ASCIIEncoding encoding;
public static void Initialize(IPAddress allowedIPAddress, int port)
{
endPoint = new IPEndPoint(allowedIPAddress, port);
tcpServer = new TcpListener(endPoint);
clients = new List<Client>();
threadListen = new Thread(new ThreadStart(Listen));
encoding = new ASCIIEncoding();
}
public static void Start()
{
threadListen.Start();
}
public static byte[] PacketToArray(Packet packet)
{
IFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
Serializer.Serialize<Packet>(stream, packet);
byte[] packetArray = stream.GetBuffer();
stream.Close();
return packetArray;
}
public static Packet ArrayToPacket(byte[] array)
{
IFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream(array);
Packet packet = new Packet();
packet = Serializer.Deserialize<Packet>(stream);
stream.Close();
return packet;
}
public static void Send(Client target, Packet packet)
{
byte[] packetArray = PacketToArray(packet);
target.networkStream.Write(packetArray, 0, packetArray.Length);
target.networkStream.Flush();
OnSend(packet);
}
private static void Listen()
{
tcpServer.Start();
OnStart();
while (true)
{
try
{
Client client = new Client();
client.tcpClient = tcpServer.AcceptTcpClient();
client.networkStream = client.tcpClient.GetStream();
client.thread = new Thread(new ParameterizedThreadStart(HandleCommunication));
clients.Add(client);
client.thread.Start(client);
OnJoin(client);
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
break;
}
}
}
private static void HandleCommunication(object client)
{
Client handleClient = (Client) client;
byte[] messageBuffer = new byte[4096];
int bytesRead = 0;
while (true)
{
bytesRead = 0;
try
{
bytesRead = handleClient.networkStream.Read(messageBuffer, 0, messageBuffer.Length);
}
catch
{
clients.Remove(handleClient);
OnLeave(handleClient);
break;
}
if (bytesRead == 0)
{
Packet packet = ArrayToPacket(messageBuffer);
OnReceive(packet);
}
}
}
private static void OnStart()
{
Console.WriteLine("Server started.");
}
private static void OnJoin(Client client)
{
Console.WriteLine("Client [ID] connected.");
Send(client, PacketGenerator.Generate(OpCodes.opHandshake, null));
}
private static void OnLeave(Client client)
{
Console.WriteLine("Client [ID] disconnected.");
}
private static void OnSend(Packet packet)
{
Console.WriteLine("Server: " + packet.opcode.ToString() + " | " + packet.message);
}
private static void OnReceive(Packet packet)
{
Console.WriteLine("Client [ID]: " + packet.opcode.ToString() + " | " + packet.message);
}
public struct Client
{
public TcpClient tcpClient;
public NetworkStream networkStream;
public Thread thread;
}
}
这是客户端类:
[ProtoContract]
public struct Packet
{
[ProtoMember(1)]
public int opcode;
[ProtoMember(2)]
public string message;
}
public static class Client
{
private static IPEndPoint endPoint;
private static TcpClient tcpClient;
private static NetworkStream networkStream;
private static Thread threadCommunication;
private static ASCIIEncoding encoding;
public static void Initialize(string ipAddress, int port)
{
endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
tcpClient = new TcpClient();
networkStream = null;
threadCommunication = new Thread(new ThreadStart(HandleCommunication));
encoding = new ASCIIEncoding();
}
public static void Connect()
{
tcpClient.Connect(endPoint);
threadCommunication.Start();
Console.WriteLine("Connected to server.");
networkStream = tcpClient.GetStream();
}
public static byte[] PacketToArray(Packet packet)
{
IFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
Serializer.Serialize<Packet>(stream, packet);
byte[] packetArray = stream.GetBuffer();
stream.Close();
return packetArray;
}
public static Packet ArrayToPacket(byte[] array)
{
IFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream(array);
Packet packet = new Packet();
packet = Serializer.Deserialize<Packet>(stream);
stream.Close();
return packet;
}
public static void Send(Packet packet)
{
byte[] packetArray = PacketToArray(packet);
networkStream.Write(packetArray, 0, packetArray.Length);
networkStream.Flush();
OnSend(packet);
}
private static void HandleCommunication()
{
byte[] messageBuffer = new byte[4096];
int bytesRead = 0;
while (true)
{
bytesRead = 0;
try
{
bytesRead = networkStream.Read(messageBuffer, 0, messageBuffer.Length);
}
catch
{
Console.WriteLine("Connection closed.");
break;
}
if (bytesRead == 0)
{
Packet packet = ArrayToPacket(messageBuffer);
OnReceive(packet);
}
}
}
private static void OnSend(Packet packet)
{
Console.WriteLine("Client [ID]: " + packet.opcode.ToString() + " | " + packet.message);
}
private static void OnReceive(Packet packet)
{
Console.WriteLine("Server: " + packet.opcode.ToString() + " | " + packet.message);
switch (packet.opcode)
{
case OpCodes.opHandshake:
Send(PacketGenerator.Generate(OpCodes.opHandshake, null));
break;
}
}
}
类型由其程序集确定作用域,BinaryFormatter序列化类型元数据(程序集限定名称等)。在两个位置拥有相同class
的副本是不够的:它们不是相同的类型,除非它们来自同一程序集。
还要注意,BinaryFormatter
在线路上存储的内容非常冗长。如果你想要解决这两个问题而不需要手动进行所有序列化的东西,那么protobuf-net会有所帮助:
- 它在电线上很密
- 它不局限于特定的类型;只要A和B看起来相似,就可以用A序列化,用B反序列化
例如:
[ProtoContract]
public struct Packet {
[ProtoMember(1)] public int opcode;
[ProtoMember(2)] public string message;
}
并且使用CCD_ 3而不是CCD_。