MoonKnight
MoonKnight

Reputation: 23833

Cross-Platform Protobuf Serialization

I have three applications that are communicating via ZeroMQ all performing different operations. The different applications are as follows:

  1. The first is a C++ application which is an engine for "hard work", this takes a Protobuf message as a request from a client, does some work, and returns a Protobuf message back to that client (or whoever is connected, Request/Reply Pattern). This uses 0MQ version 4.0.4 and using protobuf-2.6.0 where we have built the required header files ourselves, the Protobuf classes were created by protoc.

  2. Second I have a Java code and is a data provider, this uses jeromq-0.3.4.jar for the ZeroMQ messaging and protobuf-java-2.6.1.jar for the Protobuf serialization etc.

  3. Third I have a C# code which performs some analysis and has a nice UI etc. This uses Marc Gravell's protobuf-net (https://www.nuget.org/packages/protobuf-net/) as a NuGet package and NetMQ (native C# port of ZeroMQ) for the messaging.

Now, C++ <-> Java works great and with out problems, however, C++ <-> C# does not work correctly. When I send a basic request from C# to the C++ "server" via

using (NetMQContext context = NetMQContext.Create())
using (var requestSocket = context.CreateRequestSocket())
{
    requestSocket.Connect(_requestAddress); // "tcp://127.0.0.1:6500"
    requestSocket.Send(mux.ToByteArray<Taurus.FeedMux>());
}

with

public static byte[] ToByteArray<T>(this T o) 
    where T : ProtoBuf.IExtensible
{
    if (o == null)
        return null;
    using (MemoryStream ms = new MemoryStream())
    {
        ProtoBuf.Serializer.Serialize(ms, o);
        return ms.ToArray();
    }
}

The C++ code receives the message but despite setting a mandatory

Taurus.FeedMux mux = new Taurus.FeedMux();
mux.type = Taurus.FeedMux.Type.OXX;
mux.oxx = Oxx.GetOxx();

I get an error in the C++ application

[libprotobuff ERROR ..\\message_lite.cc:123] Can't parse message of type "Taurus.FeedMux" because it is missing required fields: type

But I am clearly setting type and in the C++ code, type seems to be set (using the debugger to inspect the deserialized object). I have tried two different Protobuf libraries (one I built and Mark Gravell's library via NuGet) as I thought this was a serialization issue , but this does not fix this problem.

I have also tried the clrZMQ wrapper library as well as the C# native NetMQ library, again this does not help, message is received using any combination of the above, but the received seems corrupt in some way.

What could be going wrong here and is there anything I should be doing that I have not mentioned?

Upvotes: 2

Views: 1512

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062770

My guess is that type is being treated as optional, where-as in the C++ it is marked as required. I can't see how your model is defined in the C#, but if you're using protobuf-net's attributes, you can force it to serialize via the IsRequired attribute member:

[ProtoMember(42, IsRequired = true)] // change the number!
public Taurus.FeedMux.Type type {get;set;}

Upvotes: 1

Related Questions