Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does my protobuf-net stream not work?

I have an object that can be serialized and deserialized but upon deserialization it throws me an error:

Invalid field in source data: 0

I don't know why this is happening

code for de-serialization and receiving:

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();


        }
    }

Code for serialization:

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();

    }
like image 236
user2928070 Avatar asked Oct 28 '13 12:10

user2928070


1 Answers

The root object in a protobuf message, as defined by the google specification, does not include any notion of the end of the message. This is intentional, so that concatenation is identical to merging two fragments. Consequently, the consuming code needs to restrict itself to a single message. This is identical between all protobuf implementations, and is not specific for protobuf-net.

What is happening is that your buffer is currently oversized, with garbage at the end. Currently (because you are reading one message) that garbage is most likely all zeros, and a zero is not a valid marker for a field. However, when re-using the buffer the garbage could be... anything.

In your case, probably the easiest way to do this is to use the SerializeWithLengthPrefix / DeserializeWithLengthPrefix methods, which handle all this for you by prepending the payload length at the start of the message, and only processing that much data.

As a final thought: it is not clear to me that your code will guarantee that is has read an entire message; a single receive could (on TCP, at least) return part of a message - or 2 and a bit messages, etc: TCP is stream-based, not message-based.

like image 97
Marc Gravell Avatar answered Nov 15 '22 22:11

Marc Gravell