【问题标题】:C# protobuf Deserialize Error with ZMQ, invalid write-typeC# protobuf 使用 ZMQ 反序列化错误,写入类型无效
【发布时间】:2018-12-18 11:11:51
【问题描述】:

我有两个程序。用服务器创建 发现服务器消息 并通过protobuf序列化并通过ZMQ发送。在客户端反序列化消息但错误:

Ivalid wire-type; this usually means you have over-written a file without truncating or setting the length.

我在 dll 项目中有以下类。

[ProtoContract]
public class DiscoverServerMessage 
{
    [ProtoMember(1)]
    public int Port { get; set; }
    [ProtoMember(2)]
    public string IP { get; set; }
    [ProtoMember(3)]
    public string ServerName { get; set; }
    public DiscoverServerMessage() { }
}

在服务器项目中有这个代码:

public class Server
{
    static void Main(string[] args)
    {
        ZContext ctx = new ZContext();
        ZSocket broadcastSrocket = new ZSocket(ctx, ZSocketType.PUB);
        broadcastSrocket.Connect("tcp://127.0.0.1:2666");
        ZFrame zfr;
        DiscoverServerMessage message = new DiscoverServerMessage() { Port = 2667 , ServerName = "My" };
        message.IP = "127.0.0.1";
        using (MemoryStream str = new MemoryStream())
        {
            Serializer.SerializeWithLengthPrefix(str,message,PrefixStyle.Fixed32);
            zfr = new ZFrame(str.ToArray());
        }
        broadcastSrocket.Send(zfr);
    }
}

在客户端程序中:

public class Server
{
    static void Main(string[] args)
    {
        ZContext ctx = new ZContext();
        ZSocket subSocket = new ZSocket(ctx, ZSocketType.SUB);
        subSocket.Connect("tcp://127.0.0.1:2666");
        subSocket.SubscribeAll();
        ZError err;
        ZFrame zfr = subSocket.ReceiveFrame(out err);
        DiscoverServerMessage message;
        using (MemoryStream stream = new MemoryStream(zfr.Read()))
        {
            message = Serializer.DeserializeWithLengthPrefix<DiscoverServerMessage >(stream,PrefixStyle.Fixed32);
        }
    }
}

我的错误是什么?

【问题讨论】:

  • 注意 - 在客户端代码中,您的意思是 DeserializeWithLengthPrefix&lt;DiscoverServerMessage&gt; 吗? (您输入了&lt;T&gt;,但这不是通用代码)
  • 谢谢你。我编辑我的问题

标签: c# deserialization zeromq protobuf-net


【解决方案1】:

要做的第一件事是忘记序列化部分,只需检查您发送的内容是否是您收到的内容,所以 - 获取 str.ToArray() 的副本(服务器)和将其与zfr.Read() 的任何内容(客户端)进行比较。如果两个有效载荷不相同:所有其他赌注都关闭。最简单的方法通常是通过十六进制,所以:

(服务器):

byte[] blob = str.ToArray();
string hex = BitConverter.ToString(blob); // <== get a copy of this somehow
zfr = new ZFrame(blob);
...

(客户)

byte[] blob = zfr.Read();
string hex = BitConverter.ToString(blob); // <== get a copy of this somehow
using (MemoryStream stream = new MemoryStream(blob))
...

然后检查一下:这两个十六进制序列是否相同?

注意:由于您使用的是成帧协议 (ZFrame),因此您实际上并不需要此处的长度前缀,但是......它应该不会受到伤害。 看起来您在这里的每一端都使用了适当的代码 - 以下(受您的代码影响)工作正常:

static class Program
{
    static void Main()
    {
        byte[] blob;

        // taken from server code
        using (MemoryStream str = new MemoryStream())
        {
            DiscoverServerMessage message = new DiscoverServerMessage() { Port = 2667, ServerName = "My" };
            message.IP = "127.0.0.1";

            Serializer.SerializeWithLengthPrefix(str, message, PrefixStyle.Fixed32);
            blob = str.ToArray();
        }
        System.Console.WriteLine(BitConverter.ToString(blob));

        // taken from client code
        using (MemoryStream stream = new MemoryStream(blob))
        {
            DiscoverServerMessage message;
            message = Serializer.DeserializeWithLengthPrefix<DiscoverServerMessage>(stream, PrefixStyle.Fixed32);
            Console.WriteLine(message.Port);
            Console.WriteLine(message.ServerName);
            Console.WriteLine(message.IP);
        }

    }
}

这里的输出是:

12-00-00-00-08-EB-14-12-09-31-32-37-2E-30-2E-30-2E-31-1A-02-4D-79
2667
My
127.0.0.1

如果我们只使用Serialize/Deserialize(没有长度前缀)做同样的事情,我们(可以预见)得到:

08-EB-14-12-09-31-32-37-2E-30-2E-30-2E-31-1A-02-4D-79
2667
My
127.0.0.1

所以它应该在有或没有长度前缀的情况下工作,只要客户端和服务器同意(它们在您的代码中出现)。

【讨论】:

  • 我检查了两个十六进制序列。他们是一样的。
  • @sharafi 他们是我上面展示的系列吗? (对于相同的数据,我的意思是)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
  • 2010-10-15
  • 1970-01-01
  • 1970-01-01
  • 2012-02-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多