C++ 中的 Google ProtoBuf 与 C# 中的 Protobuf-net 聊天(UDP)
Googles ProtoBuf on C++ chatting with Protobuf-net on C# (UDP)
关于这两个 Protobuf,我有一个大问题。
我有一个 Server/Client 使用 Googles Protobuf 的 C++ 应用程序。
效果很好。
客户端将数据发送到服务器,服务器应分发此消息
给其他客户。
C++ 客户端是一个纯发送方,将 Protobuf-Struct 打包在一个固定大小 (500 atm) 的字符数组中。
C++ 服务器反序列化它,查找命令(登录注销或给其他人的消息),并且(如果它是消息)将它发送到 C# 客户端。
这也是通过 500 个字符的固定大小来完成的。
这个效果很好。
现在在 C# 方面:
C# 客户端atm 可以使用Protobuf-net 登录和发送消息。即使 Protobuf-Net 将其打包为具有动态大小的字节数组(与 c++ 端的字符数组不同,它是无符号的),这仍然非常有效。
即便如此,服务器也能识别出 Message 并将其打印出来。
但是当服务器从 c++-Client 转发消息时(这是一个奇怪的问题)我在 C# 中遇到了大问题。
注:客户端是Unity3D实现的
Unity 几乎可以正常接收字节数组。
需要注意的一件事是,与服务器发送的消息不同,字节数组是未签名的。这导致 -1 变成 255.
C#-代码:
sock.ReceiveFrom (incoming, ref otherEnd);
SendPack message;
using(System.IO.MemoryStream ms =
new System.IO.MemoryStream(incoming)){
message = ProtoBuf.Serializer.Deserialize<SendPack>(ms);
print (message);
ms.Flush();
ms.Close();
}
这是 C# 客户端。
C++-代码:
char buffer[BUF];
package.serializeToArray(buffer,500);
int n = sendto(sock,buffer,BUF,0,(struct sockaddr*)
&serverAddr,sizeof(serverAddr));
这是 C++ 客户端
C++ 服务器只是将字符数组转发给 C# 客户端,
这与没有序列化部分的 UDP 客户端相同。
我收到如下错误:
原型异常:
源数据中的无效字段:0
或线型无效
编辑:
这是原始文件
syntax = "proto2"; package Messages;
message SendPack {
required int32 command = 1;
required string name = 2;
repeated RobotPart content = 3;
}
message RobotPart {
required float yaw = 1;
required float pitch = 2;
required float roll = 3;
}
对于 C++,我使用普通的 Proto-Compiler
对于 C#,我使用 -Net 编译器创建一个 CS 文件
然后从中构建库,参考 ProtoBuf.dll 统一
然后让预编译器制作一个 Serialize.dll 以包含在 Unity3D
中
好的,我重新阅读了你的代码更好。我认为问题可能与您处理 c# 服务器的方式有关。我认为您应该尝试这种方法:
MemoryStream stream = new MemoryStream(incoming, false);
ModelSerializer 序列化器 = new ModelSerializer();
message = (SendPack) serializer.Deserialize (stream, incoming, typeof (incoming));
好的。我现在找到了答案。
如果传入消息的长度不是 Protobuf 的确切字节大小(在我的例子中是 500),Protobuf-Net 就会有真正的问题。
我这样修改了我的 C++ 服务器:
int size = package.ByteSize();
char message[size];
package.SerializeToArray(message,size);
然后用这个尺寸发送。
正如我在我的 OP 中提到的,C++ 版本可以
处理打包到固定大小数组中的消息
并对其进行解码。
现在在 C# 部分我需要做一些工作。
我仍然收到一条消息并将其放入固定大小的字节数组中。
如果我只使用未初始化的数组,我会出错。
int s = sock.ReceiveFrom (incoming, ref otherEnd);
SendPack message = new SendPack();
using(System.IO.MemoryStream ms = new System.IO.MemoryStream(incoming,0,s)){
SendPackSerializer sps = new SendPackSerializer();
message = (SendPack)sps.Deserialize(ms,null,typeof(SendPack));
print (message);
ms.Flush();
ms.Close();
}
关于这两个 Protobuf,我有一个大问题。
我有一个 Server/Client 使用 Googles Protobuf 的 C++ 应用程序。 效果很好。
客户端将数据发送到服务器,服务器应分发此消息 给其他客户。
C++ 客户端是一个纯发送方,将 Protobuf-Struct 打包在一个固定大小 (500 atm) 的字符数组中。
C++ 服务器反序列化它,查找命令(登录注销或给其他人的消息),并且(如果它是消息)将它发送到 C# 客户端。 这也是通过 500 个字符的固定大小来完成的。
这个效果很好。 现在在 C# 方面:
C# 客户端atm 可以使用Protobuf-net 登录和发送消息。即使 Protobuf-Net 将其打包为具有动态大小的字节数组(与 c++ 端的字符数组不同,它是无符号的),这仍然非常有效。 即便如此,服务器也能识别出 Message 并将其打印出来。
但是当服务器从 c++-Client 转发消息时(这是一个奇怪的问题)我在 C# 中遇到了大问题。
注:客户端是Unity3D实现的
Unity 几乎可以正常接收字节数组。 需要注意的一件事是,与服务器发送的消息不同,字节数组是未签名的。这导致 -1 变成 255.
C#-代码:
sock.ReceiveFrom (incoming, ref otherEnd);
SendPack message;
using(System.IO.MemoryStream ms =
new System.IO.MemoryStream(incoming)){
message = ProtoBuf.Serializer.Deserialize<SendPack>(ms);
print (message);
ms.Flush();
ms.Close();
}
这是 C# 客户端。
C++-代码:
char buffer[BUF];
package.serializeToArray(buffer,500);
int n = sendto(sock,buffer,BUF,0,(struct sockaddr*)
&serverAddr,sizeof(serverAddr));
这是 C++ 客户端
C++ 服务器只是将字符数组转发给 C# 客户端, 这与没有序列化部分的 UDP 客户端相同。
我收到如下错误: 原型异常: 源数据中的无效字段:0
或线型无效
编辑: 这是原始文件
syntax = "proto2"; package Messages;
message SendPack {
required int32 command = 1;
required string name = 2;
repeated RobotPart content = 3;
}
message RobotPart {
required float yaw = 1;
required float pitch = 2;
required float roll = 3;
}
对于 C++,我使用普通的 Proto-Compiler 对于 C#,我使用 -Net 编译器创建一个 CS 文件 然后从中构建库,参考 ProtoBuf.dll 统一 然后让预编译器制作一个 Serialize.dll 以包含在 Unity3D
中好的,我重新阅读了你的代码更好。我认为问题可能与您处理 c# 服务器的方式有关。我认为您应该尝试这种方法:
MemoryStream stream = new MemoryStream(incoming, false);
ModelSerializer 序列化器 = new ModelSerializer();
message = (SendPack) serializer.Deserialize (stream, incoming, typeof (incoming));
好的。我现在找到了答案。
如果传入消息的长度不是 Protobuf 的确切字节大小(在我的例子中是 500),Protobuf-Net 就会有真正的问题。
我这样修改了我的 C++ 服务器:
int size = package.ByteSize();
char message[size];
package.SerializeToArray(message,size);
然后用这个尺寸发送。
正如我在我的 OP 中提到的,C++ 版本可以 处理打包到固定大小数组中的消息 并对其进行解码。
现在在 C# 部分我需要做一些工作。
我仍然收到一条消息并将其放入固定大小的字节数组中。 如果我只使用未初始化的数组,我会出错。
int s = sock.ReceiveFrom (incoming, ref otherEnd);
SendPack message = new SendPack();
using(System.IO.MemoryStream ms = new System.IO.MemoryStream(incoming,0,s)){
SendPackSerializer sps = new SendPackSerializer();
message = (SendPack)sps.Deserialize(ms,null,typeof(SendPack));
print (message);
ms.Flush();
ms.Close();
}