SerializationException при десериализации сообщения, отправляемого через сокет - PullRequest
0 голосов
/ 08 октября 2019

Я создаю программу, в которой я пытаюсь соединить сервер и несколько клиентов через систему сокетов. По какой-то причине при десериализации я получаю исключение.

Я сделал это так, чтобы первые 2 байта первого сообщения содержали длину приходящего сообщения. (Это так, чтобы я мог получать сообщения больше, чем буфер (1024 байта)). И ошибка, которую я имею, вероятно, связана с этим кодом?

Исключение:

System.Runtime.Serialization.SerializationException: 'Binary stream' 0 'не содержит действительный BinaryHeader. Возможные причины: неверное изменение потока или версии объекта между сериализацией и десериализацией. '

Базовый код отправки:

    public void Send(byte[] data)
    {
        if (ClientSocket != null && ClientSocket.Connected)
        {
            ClientSocket.BeginSend(AddSize(data), 0, data.Length, 0, ResponseSend, this);
        }
        else
        {
            ConnectionFailed();
        }
    }

    private byte[] AddSize(byte[] data)
    {
        var newData = BitConverter.GetBytes(Convert.ToUInt16(data.Length));
        Array.Resize(ref newData, sizeof(ushort) + data.Length);
        Array.Copy(data, 0, newData, sizeof(ushort), data.Length);
        return newData;
    }

    private void ResponseSend(IAsyncResult ar)
    {
        try
        {
            // Complete sending the data to the remote device.  
            var bytesSent = ClientSocket.EndSend(ar);
            SendCompleted();
        }
        catch (SocketException ex)
        {
            ConnectionFailed();
        }
    }

Базовый код приема выглядит следующим образом:

    private const int BufferSize = 1024;

    // Receive buffer.  
    private MemoryStream _bufferStream = new MemoryStream();
    private readonly byte[] _buffer = new byte[BufferSize];
    private ushort _messageLength;

    public void Receive()
    {
        if (ClientSocket != null && ClientSocket.Connected)
        {
            ClientSocket.BeginReceive(_buffer, 0, BufferSize, SocketFlags.None, ReceiveCommand, this);
        }
        else
        {
            ConnectionFailed();
        }
    }

    private void ReceiveCommand(IAsyncResult ar)
    {
        // Retrieve the socket from the state object.  
        var client = (BaseClient)ar.AsyncState;

        try
        {
            var bytesRead = ClientSocket.EndReceive(ar);
            if (bytesRead <= 0)
            {
                ConnectionFailed();
                return;
            }

            var messageSizeOffset = 0;
            if (_messageLength == 0)
            {
                _messageLength = GetMessageLength(client._buffer);
                messageSizeOffset = sizeof(ushort);
            }

            _bufferStream.Write(client._buffer, messageSizeOffset, bytesRead - messageSizeOffset);

            if (_bufferStream.Length >= _messageLength)
            {
                var data = Deserialize(_bufferStream);

                //Cleanup
                _messageLength = 0;
                _bufferStream.Dispose();
                _bufferStream = new MemoryStream();

                ReceiveCompleted(data);
            }

            Receive();
        }
        catch (SocketException ex)
        {
            ConnectionFailed();
        }
    }

И я просто использую эти простые функции сериализации и десериализации:

    private byte[] Serialize(object item)
    {
        MemoryStream stream = new MemoryStream();
        IFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, item);
        return stream.ToArray();
    }

    public static object Deserialize(MemoryStream stream)
    {
        var binaryFormatter = new BinaryFormatter();
        stream.Seek(0, SeekOrigin.Begin);
        return binaryFormatter.Deserialize(stream);
    }

Есть ли у кого-нибудьидея, почему я получаю эту ошибку? Потому что я больше не имею понятия.

Я также добавил образец по следующей ссылке: https://github.com/kevingoos/SocketTest

1 Ответ

1 голос
/ 09 октября 2019

Здесь в Send:

public void Send(byte[] data)
    {
        if (ClientSocket != null && ClientSocket.Connected)
        {
            ClientSocket.BeginSend(AddSize(data), 0, data.Length, 0, ResponseSend, this);
        }
        else
        {
            ConnectionFailed();
        }
    }

вы отправляете data.Length байт, но методы AddSize() добавляют поле длины сообщения ushort в начале буфера. Размер этого поля должен быть включен в то, что отсылается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...