套接字,接收序列化异常

时间:2015-02-19 23:26:00

标签: c# .net sockets serialization

首先,我已经阅读了StackOverflow和其他地方的许多指南和帖子,但仍然没有解决这个问题。我最近一直试图了解套接字,这证明是一个挑战。我已经了解如何使用带字符串等的套接字但我知道要开始发送对象,以便我可以更好地组织我的程序。我正在聊天客户端;服务器将连接多个客户端,它会像IRC一样工作。我已经完成了服务器的基础知识;我有方法来检查收到的数据包类型(所有数据包都继承自Packet),并有一个非常基本的switch语句,根据收到的数据包采取行动。在此之前,我显然需要将套接字中收到的byte[]转换为Packet。当我试图反序列化字节数组时,问题出现了。我在我调用的行上获得了一个SerilizationException .Deserialize();这是文字:

  

System.Runtime.Serialization.SerializationException未处理   用户代码HResult = -2146233076消息=无法找到程序集   'Client,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'。

我不明白为什么会这样;我曾尝试编写不同的反序列化数组的方法,添加随机的if语句以确保我没有传递一个空数组(我不是这样)但是不能让它在我的生活中工作。我希望有人可以指出我做错了什么?我是否会通过套接字发送对象错误?我是否只是错过了我的代码中的基本内容?

我已经包含了我的客户端的准系统(它所做的只是发送一个带有字符串的MessagePacket,我的服务器也包括在内。现在,这个程序不是最漂亮的,所以我道歉提前;这对我来说都是一个学习曲线!

服务器:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Chat_Application.Packets;

namespace Chat_Application
{
    class Server
    {
        private const int port = 1090;
        private readonly ManualResetEvent allDone;
        private readonly Dictionary<String, Socket> connections; // will hold all client sockets
        private readonly IPAddress ipAddress;
        private readonly IPEndPoint ipEndPoint;
        private readonly Thread listenThread; // seperate thread to run the server 
        private readonly Socket serverSocket;

        public Server()
        {
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            connections = new Dictionary<string, Socket>();
            ipAddress = IPAddress.Parse(GetLocalIPv4(NetworkInterfaceType.Ethernet));
            ipEndPoint = new IPEndPoint(ipAddress, port);
            listenThread = new Thread(StartListen);
            allDone = new ManualResetEvent(false);
        }

        //called to start the new thread 
        public void Start()
        {
            listenThread.Start();
        }

        //TODO: implement this method
        public void Stop()
        {
            throw new NotImplementedException();
        }

        //method that is run on the new server thread
        public void StartListen()
        {
            serverSocket.Bind(ipEndPoint);
            serverSocket.Listen(20);
            String statusUpdate = "\n<INFO> Socket bound, listening for connections...";
            Program.mainWin.AddConsoleText(statusUpdate);

            while (true)
            {
                allDone.Reset();
                serverSocket.BeginAccept(AcceptConnectionAsync, serverSocket);
                allDone.WaitOne();
            }
        }

        //Asynchronus method to recieve connections. The logic of the way things are done is not great, it is only temporary while I learn better ways to do things
        public void AcceptConnectionAsync(IAsyncResult ar)
        {
            var bufferBytes = new byte[1024];
            Packet packet = null;


            allDone.Set();

            var listener = (Socket) ar.AsyncState;
            var client = listener.EndAccept(ar);

            client.Receive(bufferBytes);

            packet = ConvertPacket(bufferBytes);

            switch (CheckPacketType(packet))
            {
                case PacketType.Message:
                    packet = ConvertPacket(bufferBytes);
                    var messagePacket = (MessagePacket) packet;
                    String userMessage = "(" + messagePacket.userName + ") " +
                                            Encoding.UTF8.GetString(messagePacket.message);
                    Program.mainWin.AddConsoleText(userMessage);
                    break;

                case PacketType.Connection:
                    packet = ConvertPacket(bufferBytes);
                    var connectionPacket = (Connect) packet;
                    String connectionMessage = "\n<CONNECT>New connection established to " +
                                                connectionPacket.userName;
                    connections.Add(connectionPacket.userName, client);
                    Program.mainWin.AddConsoleText(connectionMessage);
                    break;

                case PacketType.Command:
                    // TODO Implement this case, add new packet type
                    packet = ConvertPacket(bufferBytes);
                    var commandPacket = (MessagePacket) packet;
                    break;

                case PacketType.Disconnect:
                    packet = ConvertPacket(bufferBytes);
                    var disconnectPacket = (Dissconnect) packet;
                    String disconnectMessage = "\n<DISCONNECT>User " + disconnectPacket.userName +
                                                " Disconnected succesffuly";
                    connections.Remove(disconnectPacket.userName);
                    if (disconnectPacket.goodDissconnect)
                    {
                        Program.mainWin.AddConsoleText(disconnectMessage);
                    }
                    else
                    {
                        String message = "\n<DISCONNECT>User " + disconnectPacket.userName +
                                            " Disconnected unexpectedly";
                        Program.mainWin.AddConsoleText(message);
                    }
                    break;

                case PacketType.Request:
                    // TODO Implement this case, add new packet type
                    packet = ConvertPacket(bufferBytes);
                    var requestPacket = (MessagePacket) packet;
                    break;

                case PacketType.Default:
                    MessageBox.Show("Packet Error", "Empty Packet Recieved");
                    break;

                default:
                    break;
            }
        }

        //used to check what type of packet has been recieved
        private PacketType CheckPacketType(Packet packet)
        {
            switch (packet.type)
            {
                case PacketType.Message:
                    return PacketType.Message;
                    break;

                case PacketType.Connection:
                    return PacketType.Connection;
                    break;

                case PacketType.Command:
                    return PacketType.Command;
                    break;

                case PacketType.Disconnect:
                    return PacketType.Disconnect;
                    break;

                case PacketType.Request:
                    return PacketType.Request;
                    break;

                default:
                    break;   
            }
            return PacketType.Default;
        }

        //converts the byte array to a packet
        private Packet ConvertPacket(byte[] bytes)
        {
            Packet packet = null;

            //try to convert byte array to a Packet, the error occurs on the last line; when trying to de-serialize
            /*try
            {*/
                var memStream = new MemoryStream();
                var binForm = new BinaryFormatter();
                memStream.Write(bytes, 0, bytes.Length);
                memStream.Seek(0, SeekOrigin.Begin);
                packet = (Packet) binForm.Deserialize(memStream);
            //}
            /*catch (Exception) // MAKE THIS THE APPROPRIATE EXCEPTION
            {
                MessageBox.Show("An unexpected error has occured when atempting to convert a packet!");
            }*/

            if (packet != null)
            {
                return packet;
            }
            else
            {
                MessageBox.Show("Error converting packet!");
                return null;
            }
        }

        //gets the local ip
        public string GetLocalIPv4(NetworkInterfaceType _type)
        {
            var output = "";
            foreach (var item in NetworkInterface.GetAllNetworkInterfaces())
            {
                if (item.NetworkInterfaceType == _type && item.OperationalStatus == OperationalStatus.Up)
                {
                    foreach (var ip in item.GetIPProperties().UnicastAddresses)
                    {
                        if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            output = ip.Address.ToString();
                        }
                    }
                }
            }
            return output;
        }
    }
}

客户端:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Chat_Application.Packets;

namespace Client
{
    public partial class ClientWindow : Form
    {

        public ClientWindow()
        {
            InitializeComponent();
        }

        private void ClientWindow_Load(object sender, EventArgs e)
        {
            MessagePacket packet = new MessagePacket("Chris", "Hello Server!");
            byte[] data;
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(new IPEndPoint(IPAddress.Parse(GetLocalIPv4(NetworkInterfaceType.Ethernet)), 1090));
            packet.type = PacketType.Message;
            data = ConvertPacket(packet);

            //to check if the packet has been converted correctly
            if (data != null)
            {
                socket.Send(data);
            }


        }

        public string GetLocalIPv4(NetworkInterfaceType _type)
        {
            string output = "";
            foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
            {
                if (item.NetworkInterfaceType == _type && item.OperationalStatus == OperationalStatus.Up)
                {
                    foreach (UnicastIPAddressInformation ip in item.GetIPProperties().UnicastAddresses)
                    {
                        if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            output = ip.Address.ToString();
                        }
                    }
                }
            }
            return output;
        }


        private byte[] ConvertPacket(Packet packet)
        {
            byte[] bytes = new byte[1024];
            BinaryFormatter formatter = new BinaryFormatter();

            using (MemoryStream ms = new MemoryStream())
            {
                formatter.Serialize(ms, packet);
                bytes = ms.ToArray();
            }
            return bytes;
        }



    }
}

1 个答案:

答案 0 :(得分:1)

这个例外对我来说非常清楚。当您尝试反序列化数据时,显然找不到序列化数据时引用的Client程序集。

不幸的是,您的代码示例不包含有关您声明Packet类的位置和方式的信息。但根据您报告的行为,我似乎可能已将相同的.cs文件链接到两个不同的项目,结果是每个程序集都使用自己的Packet类型的私有副本。

如果是这种情况,那么问题至少有几个很好的解决方案:

  1. 仅在一个装配体中定义类型,并根据需要引用该装配体。例如,您可以在Client.dll程序集中定义它,然后添加Client.dll程序集作为Server.dll程序集的参考。或者您可以构建包含该类型的第三个程序集,并使Client.dllServer.dll程序集引用该第三个程序集。
  2. 请改用XmlSerializer。 XML不包含需要特定程序集来定义相关类型的类型信息。当使用XmlSerializer映射到.NET之外的XML(即无法共享公共程序集以定义类型)时,这种情况更常用,但这种方法可以解决您的具体问题也
  3. 就个人而言,我选择#1选项,并将该类型放入客户端和服务器共享的DLL中。