Сериализация и десериализация двоичного форматера C # - 3 случайных исключения - PullRequest
0 голосов
/ 03 марта 2019

Я создаю приложение на C # (клиент и сервер).Это отдельные проекты, и обе они ссылаются на DLL, которая может сериализовать и десериализовать любой объект, который в них вставлен.

Все работает нормально, пока я не начну работать с мониторингом рабочего стола в реальном времени (Video-ish).DLL содержит пользовательский класс «Снимок экрана» , который принимает растровое изображение и записывает его в общий поток памяти для этого класса.Вот как все это делается:

  1. Кнопка клиента делает снимок всего экрана (в виде растрового изображения)
  2. Клиент создает объект Screenshot , сериализует его,и отправляет его на сервер.(Сериализация превращает его в байты) Затем клиент повторяет эти шаги для постоянной отправки снимков экрана
  3. Сервер получает эти байты, десериализует его, проверяет, является ли он типом Снимок экрана , затем вызывает событие и отображаетэто изображение в форме, если оно истинно.

Да Я получаю прямую трансляцию изображения, и она отображается в форме, но это работает только от 3 до 10 секунд.Я получаю 3 исключения в целом, они происходят случайным образом от клиентов.

Я также опубликую снимки экрана с некоторыми подробностями о них, извините за странный блок обработчика исключений.https://imgur.com/a/Uv4r6wY


Вот код Сериализации и Десериализации внутри DLL:

    public static byte[] Serialize(Object paramObj)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, paramObj);
            return ms.ToArray();
        }
    }
    public static Object Deserialize(byte[] paramBuffer)
    {
        using (MemoryStream ms = new MemoryStream(paramBuffer))
        {
            BinaryFormatter bf = new BinaryFormatter();
            //ms.Position = 0;
            ms.Seek(0, SeekOrigin.Begin);
            return (Object)bf.Deserialize(ms);
        }
    }

Я часами изучал эти ошибки и ничего не придумал, ничего, что якажется, что это приводит к появлению еще одной ошибки.

Спасибо, что нашли время, чтобы проанализировать мой грязный код.Действительно ty.


Если вам интересно, как сервер обрабатывает полученные данные:

    public void receiveAll()
    {
        byte[] _buffer = new byte[55000];

        _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), _clientSocket);

        void ReceiveCallback(IAsyncResult AR)
        {
            try
            {
                _clientSocket = (Socket)AR.AsyncState;
                int received = _clientSocket.EndReceive(AR);
                byte[] receivedbuffer = new byte[received];
                Array.Copy(_buffer, receivedbuffer, received);

                // The "ObjectHandler" is the class to Ser & Deser in the DLL
                Object data = ObjectHandler.Deserialize(receivedbuffer);

                try 
                {
                    // Check the data that is received & determine type
                }
                catch (Exception ex)
                {
                     // Show Exception box
                }

                // Repeat the receive process...
                _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), _clientSocket);
            }
            catch (Exception ex)
            {
                RemoveClient();
                // Show Exception box
            }
        }
    }

1 Ответ

0 голосов
/ 04 марта 2019

Исключения сериализации просто означают, что данные каким-то образом неполны или повреждены.Проблема заключается в передаче данных, а не в сериализации.

Я предполагаю, что вы используете TCP-сокет для соединения?Нет никакой гарантии, что вызов чтения на Socket (или TcpClient, Stream и т. Д.) Даст вам все данные, которые вы ожидаете за один раз.Буфер заполняется числом байтов от до size из данных, которые в настоящее время доступны на принимающей стороне.Особенно при отправке больших объемов данных по сети, скорее всего, они будут поступать в виде нескольких частичных пакетов, а не одновременно.Кроме того, один приемный вызов может возвращать как конец текущего сообщения, так и начало следующего.

Вам необходимо повторно вызывать BeginReceive в цикле, пока вы не узнаете, что получили полное сообщение, например, попрефикс вручную переданных данных со значением длины на отправляющей стороне и затем ожидание, пока вы не буферизируете хотя бы тот объем данных на принимающей стороне.

...