Search code examples
c#streamipcprotobuf-netmemory-mapped-files

IPC Using Protobuf and Memory Mapped Files C#


I'm writing a project to pass an object from a parent application to a child application. I'm using Protobuf to serialize and deserialize the data. I'm also using a Non-Persisted Memory-Mapped File to write to when serializing (and read from when deserializing). Here is the code:

[ProtoContract(SkipConstructor = true)]
public class Test
{
    [ProtoMember(1)]
    public int ID { get; private set; }
    [ProtoMember(2)]
    public bool TestBool { get; private set; }
    [ProtoMember(3)]
    public string MessageBody { get; private set; }

    public Test(int id, bool testBool, string messageBody)
    {
        this.ID = id;
        this.TestBool = testBool;
        this.MessageBody = messageBody;
    }


    public void Serialize()
    {
        MemoryMappedFile mmf = MemoryMappedFile.CreateNew("testmap", 1000);
        using (MemoryMappedViewStream stream = mmf.CreateViewStream())
        {
            Serializer.SerializeWithLengthPrefix(stream, this, PrefixStyle.Base128);
            stream.Flush();
        }
    }

    public static Test Deserialize()
    {
        using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("testmap"))
        {
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                return Serializer.DeserializeWithLengthPrefix<Test>(stream, PrefixStyle.Base128);
            }
        }
    }
}

//On the parent application
var msg = new SharedLibrary.Test(1234, true, "Test message hahah");
msg.Serialize();
//spawn child application



//On the child application
Test result = Test.Deserialize();   

When I run this code I get the following error (when Serializer.Deserialize is called):

Exception thrown: 'ProtoBuf.ProtoException' in protobuf-net.dll Additional information: Invalid field in source data: 0 I think this error is occurring because The stream is larger than the actual data it contains. When the stream is deserialized I think it starts reading beyond the actual data.

Exception thrown: 'ProtoBuf.ProtoException' in protobuf-net.dll Additional information: No parameterless constructor found for Test

I'm not sure the best way to fix this however. Is there a way to read the bytes from a stream until the is no data left and then stop? If not can I solve this another way?


Solution

  • I'm not sure the best way to fix this

    1. add a parameterless constructor (it can be private if you like), or
    2. add the SkipConstructor = true as parameters on the [ProtoContract(...)] on your type

    however. Is there a way to read the bytes from a stream until the is no data left and then stop?

    Yes, that is the default in protocol buffers, since the outermost message does not include a length marker or end marker (it is designed to be appendable). However, in your case, this is probably not what you want, as there will be various garbage (possibly all zeros, possibly not) after the data you serialize. You might want to use SerializeWithLengthPrefix and DeserializeWithLengthPrefix instead. And if your data is only 1000 bytes, MemoryStream will be fine - no need to use unmanaged memory.