c# - C# protobuf 使用 ZMQ 反序列化错误,写入类型无效
问题描述
我有两个程序。使用服务器创建 DiscoverServerMessage 并通过 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);
}
}
}
我的错误是什么?
解决方案
首先要做的是忘记序列化部分,只需检查您发送的内容是否是您收到的内容,因此 - 获取任何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
因此,只要客户端和服务器同意(它们在您的代码中出现),它就可以使用或不使用长度前缀。
推荐阅读
- azure - Azure devops:分支策略
- forms - 表单提交时复选框输入仍然为假
- c# - 如何从 h4 获取此文本?
- amazon-web-services - 在 Amazon Cognito 中创建新用户并公开共享他的凭证是一种好习惯吗?
- sql - 带有 ANY 子句的 Postgres 相似性运算符 - 每个参数的限制?
- java - 如何将 completableFuture.supplyAsync() 的返回类型分配给对象?
- php - 在控制器中接收多个输入
- asynchronous - Vue中异步调用后向props传递数据
- javascript - 如果发生变化,如何在 onload 后显示所有 iframe 内容?
- java - 谁能建议如何使用firebase轻松跟踪应用程序按钮点击?