使用 ØMQ/ZMQ 序列化 Protobuf 对象并发送

Posted

技术标签:

【中文标题】使用 ØMQ/ZMQ 序列化 Protobuf 对象并发送【英文标题】:Serializing Protobuf Object and Sending with ØMQ/ZMQ 【发布时间】:2015-03-10 21:22:35 【问题描述】:

我有一个 protobuf 对象,我从 C# 应用程序(使用 clrZmq)发送到本地机器上的 C++ 服务(使用 zmq C++ 绑定)(用于测试)。我尝试使用以下命令从 C# 发送我的对象

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

我通过扩展方法将我的Taurus.Odds 对象序列化为byte[]

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

我在我的 C++ 应用程序中看到代码接收到消息,但 C++ ZMQ 类无法正确反序列化它。我有一些 Java 代码以相同的方式发送到 C++ 代码而没有问题。我的问题是,我在上面是否通过 ZMQ 正确发送了我的对象,如果不是,我做错了什么?

感谢您的宝贵时间。

【问题讨论】:

您是否尝试过使用 protobuf 中提供的基于文本的调试格式? (不确定它是否是 C# 版本,但它是 google 开发的) 如何使用这种格式来帮助我?序列化按我的预期工作并正确创建 byte 数组。我想知道我是否缺少明显的东西? 这样您就可以直观地检查Java版本和C#版本生成的格式化消息是否相同。或者您是否已经检查过它们是否逐字节相同? 太好了,我没有直接访问权限,无法直接调试 Java。我可以浏览代码库,我似乎也在做同样的事情,但你是对的。我会请我的同事帮我检查一下。感谢您的宝贵时间,我会尽快回复您... 【参考方案1】:

这是你的错误:

我正在通过扩展方法将我的Taurus.Odds 对象序列化为byte[]

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

您似乎不知道BinaryFormatter 是什么。它与 ProtoBuf 没有任何关系。 docs 说如下:

序列化和反序列化一个对象或整个连接对象图,二进制格式

这种二进制格式是特定于.NET的实现细节。而且它非常严格,版本支持很差。它主要在 .NET 远程处理时代使用,现在使用它通常被认为是一个坏主意,因为周围有更好的序列化程序。

如您所见,您的 C++ 应用无法读取它,因为它不是 protobuf 格式。

所以扔掉这个方法,用一些适当的 protobuf 序列化代码替换它,正如 in the protobuf-net docs 解释的那样。您需要在对象中添加[ProtoContract][ProtoMember] 属性。然后你可以这样写:

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

【讨论】:

以上是关于使用 ØMQ/ZMQ 序列化 Protobuf 对象并发送的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 protobuf-net 异常的代理对 List<T> 进行序列化

是否可以在 Silverlight 中使用 protobuf-net 对私有属性进行(反)序列化?

使用 c# 的 protobuf 反序列化“长”字符串对我来说不起作用

Avro 与 Protobuf 的性能指标

有没有办法让以前公开的无参数构造函数私有化,而不会对 protobuf(反)序列化进行重大更改?

netty编解码之使用protobuf