【问题标题】:binary formatter deserialize from memory stream freezing二进制格式化程序从内存流冻结反序列化
【发布时间】:2020-08-24 12:59:02
【问题描述】:

我正在尝试做一个通过套接字进行通信的客户端-服务器应用程序,它们的消息是序列化的,并使用 BinaryFormatter 反序列化。我的代码冻结并且在达到反序列化时完全没有做任何事情,我不明白为什么,因为我没有例外。我也无法使用调试器进入,一切都冻结了。这是我的代码:

 public class Serializer
    {
        public static MemoryStream ToStream(object obj)
        {
            var stream = new MemoryStream();
            var formatter = new BinaryFormatter();
            formatter.Serialize(stream, obj);
            return stream;
        }

        public static object FromStream(MemoryStream stream)
        {
            Console.WriteLine("Starting from stream");
            var formatter = new BinaryFormatter();
            stream.Seek(0, SeekOrigin.Begin);
            object rez = formatter.Deserialize(stream); //NEVER GOES OVER THIS
            Console.WriteLine("Starting deserialization" + rez);
            return formatter.Deserialize(stream);
        }
    }
public class Connection
    {
        private Socket socket;
        public Connection(Socket socket)
        {
            this.socket = socket;
            Console.WriteLine($"Connected to client: {socket.RemoteEndPoint}");
            Task.Factory.StartNew(() => Execute(socket));
        }

        private void Execute(Socket socket)
        {
            while (true)
            {
                var buffer = new byte[2048];
                var bytesCount = socket.Receive(buffer);
                if(bytesCount != 0)
                {
                    var msgReceived = (Message)Serializer.FromStream(new MemoryStream(buffer, 0, buffer.Length));
                    Console.WriteLine($"Received msg: {msgReceived.Content}");
                }
               /* var msg = new Message { Content = "Hello World2!" };
                Console.WriteLine($"Sending msg with content: {msg.Content}");
                MemoryStream stream = Serializer.ToStream(msg);
                var bytesSent = socket.Send(stream.GetBuffer());*/

                Console.WriteLine("Trying again");
                Thread.Sleep(500);
            }
        }

客户端代码:

  var host = Dns.GetHostEntry("localhost");
            var ipAddress = host.AddressList.First();
            var serverEndpoint = new IPEndPoint(ipAddress, 9000);

            Socket serverSocket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            serverSocket.Connect(serverEndpoint);

            Console.WriteLine($"Successfully connected to server on: {serverSocket.RemoteEndPoint}");

            while (true)
            {
                var msg = new Message { Content = "Hello World!" };
                Console.WriteLine($"Sending msg with content: {msg.Content}");
                MemoryStream stream = Serializer.ToStream(msg);
                var bytesSent = serverSocket.Send(stream.GetBuffer());
                Console.WriteLine("Waiting to receive");

                var buffer = new byte[2048];
                int bytesReceived = serverSocket.Receive(buffer);
                if (bytesReceived != 0)
                {
                    var receivedMessage = (Message)Serializer.FromStream(new MemoryStream(buffer));
                    Console.WriteLine($"Received message: {receivedMessage.Content}");
                }

                Console.WriteLine("Received done");

            }

服务器代码:

var host = Dns.GetHostEntry("localhost");
            var ipAddress = host.AddressList.First();
            var localEndPoint = new IPEndPoint(ipAddress, 9000);
            var serverSocket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            serverSocket.Bind(localEndPoint);
            serverSocket.Listen(1);

            while (true)
            {
                Console.WriteLine("Waiting for client");
                Socket clientSocket = serverSocket.Accept();
                var connection = new Connection(clientSocket);
            }

我还检查了 byteCount 并且它们正在到达服务器,缓冲区也不为空,我不明白为什么反序列化什么都不做..

【问题讨论】:

标签: c# sockets serialization deserialization binaryformatter


【解决方案1】:

只能同时运行一段代码。当无限循环while (true) 运行时,没有其他代码能够运行。

您需要向该项目添加一些多任务处理。每个文字处理器所需的最小数量。但是,您似乎也在控制台中编程。根据我的经验,控制台和多任务处理并不能很好地混合。您需要保持程序处于活动状态,而不会阻塞输入。

我对学习多任务的建议是 Windows 窗体中的 BackgroundWorker。 BGW 已过时,使用这些线程在这里将是不必要的,不应在生产代码中使用。但它可能是我所知道的多任务处理和线程处理的最佳“训练轮”。

【讨论】:

    【解决方案2】:

    你调用了两次反序列化,我认为问题在这里:

    object rez = formatter.Deserialize(stream); //NEVER GOES OVER THIS
    Console.WriteLine("Starting deserialization" + rez);
    return formatter.Deserialize(stream);
    

    我认为你可以使用这样的方法:

        private byte[] SerializeMessage(Message msg)
        {
            var formatter = new BinaryFormatter();
            byte[] buf;
            using (MemoryStream stream = new MemoryStream())
            {
                formatter.Serialize(stream, msg);
                buf = new byte[stream.Length];
                return stream.ToArray();
            }
        }
    
         private Message DeserializeMessage(byte[] buff)
         {
                var formatter = new BinaryFormatter();
                ConnectingMessage msg;
                using (Stream stream = new MemoryStream(buff))
                {
                    msg = formatter.Deserialize(stream) as Message;
                }
    
                return msg;           
         }
    

    Send/Receive 方法也是同步的,它们会阻塞线程执行。

    异步选项的说明在这里https://docs.microsoft.com/en-us/dotnet/framework/network-programming/using-an-asynchronous-client-socket

    【讨论】:

    • 我调用了两次,因为我试图让调试器进入反序列化方法,如果我调用一次,结果是一样的..
    • 我运行了你的代码,它工作正常,直到我们第二次尝试从流中读取的地方,那里抛出异常。尝试用return rez;替换return formatter.Deserialize(stream);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-04
    • 1970-01-01
    • 2012-05-10
    • 2016-12-31
    • 2013-09-23
    • 1970-01-01
    • 2017-12-26
    相关资源
    最近更新 更多