MoonKnight
MoonKnight

Reputation: 23833

Serializing Protobuf Object and Sending with ØMQ/ZMQ

I have a protobuf object that I am sending from a C# application (using clrZmq) to a C++ service (using the zmq C++ bindings) on a local machine (for testing). I attempt to send my object from C# using the following

Taurus.Odds odds = Util.GetFakeOdds();
using (var context = ZmqContext.Create())
using (var socket = context.CreateSocket(SocketType.REQ))
{
    byte[] buffer = null;
    socket.Connect(TARGET); // TARGET = "tcp://127.0.0.1:6500"

    Taurus.FeedMux mux = new Taurus.FeedMux();
    mux.type = Taurus.FeedMux.Type.ODDS;
    mux.odds = odds;

    SendStatus status = socket.Send(mux.ToByteArray());
    if (status == SendStatus.Sent)
    {
        int i;
        byte[] arr = socket.Receive(buffer, SocketFlags.None, out i);
        Taurus.Bet bet = buffer.ToObject<Taurus.Bet>();
    }
...
}

Where I am serializing to my Taurus.Odds object to byte[] via the extension method

public static byte[] ToByteArray(this object o)
{
     if(o == null)
          return null;
     BinaryFormatter bf = new BinaryFormatter();
     using (MemoryStream ms = new MemoryStream())
     {
         bf.Serialize(ms, o);
         return ms.ToArray();
     }
}

I see in my C++ application that the code receives the message, but the C++ ZMQ classes fail to de-serialize it correctly. I have some Java code that send to the C++ code in the same way without issue. My question is, am I sending my object via ZMQ correctly in the above and if not what am I doing wrong?

Thanks for your time.

Upvotes: 0

Views: 1655

Answers (1)

Lucas Trzesniewski
Lucas Trzesniewski

Reputation: 51330

Here's your error:

I am serializing to my Taurus.Odds object to byte[] via the extension method

...
BinaryFormatter bf = new BinaryFormatter();
...

You seem to be unaware of what BinaryFormatter is. It is in no way related to ProtoBuf. The docs say the following:

Serializes and deserializes an object, or an entire graph of connected objects, in binary format.

This binary format is a .NET-specific implementation detail. And it's very rigid at that, with poor versioning support. It was mainly used in the .NET remoting days, and it's generally considered a bad idea to use it today, as there are much better serializers around.

As you can see, there's no way your C++ app could be able to read that, as it's not in protobuf format.

So throw this method away and replace it with some proper protobuf serializing code, as explained in the protobuf-net docs. You'll need to add [ProtoContract] and [ProtoMember] attributes in your objects. Then you could write something like:

public static byte[] ToByteArray<T>(this T o)
{
     if (o == null)
          return null;

     using (MemoryStream ms = new MemoryStream())
     {
         ProtoBuf.Serializer.Serialize(ms, o);
         return ms.ToArray();
     }
}

Upvotes: 1

Related Questions