Почему мой поток protobuf-net не работает?

У меня есть объект, который можно сериализовать и десериализовать, но при десериализации он выдает ошибку:

Invalid field in source data: 0

Я не знаю, почему это происходит

код для десериализации и получения:

public void listenUDP()
{
        EndPoint ep = (EndPoint)groupEP;
        //BinaryFormatter bf = new BinaryFormatter();
        recieving_socket.Bind(ep);
        while (true)
        {

            byte[] objData = new byte[65535];
            recieving_socket.ReceiveFrom(objData, ref ep);
            MemoryStream ms = new MemoryStream();
            ms.Write(objData, 0, objData.Length);
            ms.Seek(0, SeekOrigin.Begin);

            messageHandle(ProtoBuf.Serializer.Deserialize<SimplePacket>(ms));
            ms.Dispose();


        }
    }

Код для сериализации:

public void sendDataUDP(Vec2f[] data)
    {

            SimplePacket packet = new SimplePacket(DateTime.UtcNow, data);
            //IFormatter formatter = new BinaryFormatter();
            MemoryStream stream = new MemoryStream();
            System.Diagnostics.Stopwatch st = System.Diagnostics.Stopwatch.StartNew();
            //formatter.Serialize(stream, data);
            ProtoBuf.Serializer.Serialize<SimplePacket>(stream, packet);
            //Console.WriteLine(st.ElapsedTicks);
            stream.Close();
            st.Restart();
            sending_socket.SendTo(stream.ToArray(), sending_end_point);
            //Console.WriteLine(st.ElapsedTicks);
            st.Stop();

    }

person user2928070    schedule 28.10.2013    source источник


Ответы (1)


Корневой объект в сообщении protobuf, как определено в спецификации Google, не включает никакого понятия конца сообщения. Это сделано намеренно, так что конкатенация идентична слиянию двух фрагментов. Следовательно, потребляющий код должен ограничиваться одним сообщением. Это идентично для всех реализаций protobuf и не специфично для protobuf-net.

Что происходит, так это то, что ваш буфер в настоящее время слишком большой, с мусором в конце. В настоящее время (поскольку вы читаете одно сообщение) этот мусор, скорее всего, состоит из нулей, а ноль не является допустимым маркером для поля. Однако при повторном использовании буфера мусор может быть... чем угодно.

В вашем случае, вероятно, самый простой способ сделать это - использовать методы SerializeWithLengthPrefix/DeserializeWithLengthPrefix, которые обрабатывают все это за вас, добавляя длину полезной нагрузки в начале сообщения и обрабатывая только этот объем данных.

В заключение: мне не ясно, гарантирует ли ваш код, что он прочитал все сообщение; один прием может (по крайней мере, по TCP) вернуть часть сообщения - или 2 с небольшим сообщения и т. д.: TCP основан на потоке, а не на основе сообщений.

person Marc Gravell    schedule 28.10.2013