如何通过套接字发送外部库的可序列化对象?

时间:2016-12-09 08:01:11

标签: c# sockets serialization

我有一个简单的类库,它只包含一种类型。现在我想通过使用套接字从客户端向服务器发送此类型的实例。客户端和服务器对SendingObject类型一无所知,这就是我需要加载程序集的原因。

[Serializable]
    public class SendingObject : MarshalByRefObject
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public SendingObject() { }

        public SendingObject(string firstname, string lastname)
        {
            FirstName = firstname;
            LastName = lastname;
        }

        public override string ToString()
        {
            return string.Format($"Firstname: {FirstName}. Lastname: {LastName}.");
        }
    }

这是我客户的代码:

   class Program
        {
            static void Main(string[] args)
            {   
                string path = @"path to MyLibrary.dll";
                Assembly library = Assembly.LoadFrom(path);

                Type typeObj = library.GetType("MyLibrary.SendingObject");
                var sob = Activator.CreateInstance(typeObj, new object[] {"Bob", "Smith"});

                try
                {
                    SendAddUserMessageFromSocket(83, sob);
                }
                catch (Exception exc)
                {
                    Console.WriteLine(exc.Message);
                }

                Console.WriteLine("\nTap to continue...");
                Console.ReadKey(true);
            }

            static void SendAddUserMessageFromSocket(int port, object obj)
            {    
                byte[] brr = ObjectToByteArray(obj);

                IPHostEntry ipHost = Dns.GetHostEntry("localhost");
                IPAddress ipAddress = ipHost.AddressList[0];
                IPEndPoint endPoint = new IPEndPoint(ipAddress, port);

                Socket sender = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                sender.Connect(endPoint);

                NetworkStream networkStream = new NetworkStream(sender);

                if (networkStream.CanWrite)
                {
                    networkStream.Write(brr, 0, brr.Length);
                }

                Console.WriteLine("The message was sent.");
            }

            // Convert an object to a byte array
            private static byte[] ObjectToByteArray(Object obj)
            {
                if (obj == null)
                    return null;

                BinaryFormatter bf = new BinaryFormatter();
                MemoryStream ms = new MemoryStream();
                bf.Serialize(ms, obj);

                return ms.ToArray();
            }

            // Convert a byte array to an Object
            private static Object ByteArrayToObject(byte[] arrBytes)
            {
                MemoryStream memStream = new MemoryStream();
                BinaryFormatter binForm = new BinaryFormatter();
                memStream.Write(arrBytes, 0, arrBytes.Length);
                memStream.Seek(0, SeekOrigin.Begin);
                Object obj = (Object)binForm.Deserialize(memStream);

                return obj;
            }
        }

此接收的对象将在服务器端反序列化。这是我服务器的代码。

class Program
    {
        static void Main(string[] args)
        {
            IPHostEntry ipHost = Dns.GetHostEntry("localhost");
            IPAddress ipAddr = ipHost.AddressList[0];
            IPEndPoint endPoint = new IPEndPoint(ipAddr, 83);
            Socket socketListener = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            string path = @"path to MyLibrary.dll";
            Assembly library = Assembly.LoadFrom(path);
            Type typeObj = library.GetType("MyLibrary.SendingObject");

            try
            {
                socketListener.Bind(endPoint);
                socketListener.Listen(10);
                bool isWorkFinished = false;

                while (!isWorkFinished)
                {
                    Socket handler = socketListener.Accept();
                    byte[] bytes = new byte[2064];

                    // Get data from connected socket to buffer
                    int numberOfReceivedBytes = handler.Receive(bytes);

                    byte[] bytesObject = new byte[numberOfReceivedBytes];

                    for (int i = 0; i < numberOfReceivedBytes; i++)
                        bytesObject[i] = bytes[i];

                    object res = ByteArrayToObject(bytesObject);
                }
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
            }

            Console.WriteLine("\nTap to continue...");
            Console.ReadKey(true);
        }

        // Convert an object to a byte array
        private static byte[] ObjectToByteArray(Object obj)
        {
            if (obj == null)
                return null;

            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            bf.Serialize(ms, obj);

            return ms.ToArray();
        }

        // Convert a byte array to an Object
        private static Object ByteArrayToObject(byte[] arrBytes)
        {
            MemoryStream memStream = new MemoryStream();
            BinaryFormatter binForm = new BinaryFormatter();
            memStream.Write(arrBytes, 0, arrBytes.Length);
            memStream.Seek(0, SeekOrigin.Begin);
            Object obj = (Object)binForm.Deserialize(memStream);

            return obj;
        }
    }

我的SendingObject可以序列化,但是我在尝试反序列化时遇到错误。

  

无法找到程序集:“MyLibrary,Version = 1.0.0.0,   Culture = neutral,PublicKeyToken = null“。

1 个答案:

答案 0 :(得分:0)

好的,基本的东西,.NET中的二进制序列化可以用TypeAssembly等信息来指出那些二进制文件。这就是为什么初学者可以更容易地使用库来序列化数据这将阻止对所有对象的引用。例如:

// assume this is Me.Serialization.Library.csproj
public class MeSerializer {
    public static byte[] Serialize<T>(T obj){
        // serialization method
    }

    public static T Deserialize<T>(byte[] buffer) {
        // deserialization method
    }
}

现在在其他两个项目中(假设是客户端和服务器),您只需使用Me.Serialization.Library中的方法,如:

static void SendAddUserMessageFromSocket(int port, object obj)
{    
    // simple edit :
    string path = @"path to MyLibrary.dll";
    Assembly library = Assembly.LoadFrom(path);

    Type typeObj = library.GetType("MyLibrary.SendingObject")
    MethodInfo method = typeof(Me.Serialization.Library.MeSerializer).GetMethod("Serialize");
    MethodInfo generic = method.MakeGenericMethod(typeObj);
    byte[] brr = (byte[])generic.Invoke(null, obj); // null because it is static

    // remember to add reference to Me.Serialization.Library
    // byte[] brr = Me.Serialization.Library.MeSerializer.Serialize<MyLibrary.SendingObject>(obj);

    IPHostEntry ipHost = Dns.GetHostEntry("localhost");
    IPAddress ipAddress = ipHost.AddressList[0];
    // skipped rest of the code for readability
}

在另一个项目中也这样做:

// simple edit :
string path = @"path to MyLibrary.dll";
Assembly library = Assembly.LoadFrom(path);

Type typeObj = library.GetType("MyLibrary.SendingObject")
MethodInfo method = typeof(Me.Serialization.Library.MeSerializer).GetMethod("Deserialize");
MethodInfo generic = method.MakeGenericMethod(typeObj);

// remember to add reference to Me.Serialization.Library
while (!isWorkFinished)
{
    Socket handler = socketListener.Accept();
    byte[] bytes = new byte[2064];

    // Get data from connected socket to buffer
    int numberOfReceivedBytes = handler.Receive(bytes);

    byte[] bytesObject = new byte[numberOfReceivedBytes];

    for (int i = 0; i < numberOfReceivedBytes; i++)
        bytesObject[i] = bytes[i];

    object brr = (object)generic.Invoke(null, bytesObject);
    // object res = (object)Me.Serialization.Library.MeSerializer.Deserialize<MeLibrary.SendingObject>(bytesObject);
}