C++ 中的 Google ProtoBuf 与 C# (UDP) 中的 Protobuf-net 聊天
Posted
技术标签:
【中文标题】C++ 中的 Google ProtoBuf 与 C# (UDP) 中的 Protobuf-net 聊天【英文标题】:Googles ProtoBuf on C++ chatting with Protobuf-net on C# (UDP) 【发布时间】:2016-06-28 20:34:15 【问题描述】:关于这两个 Protobuf,我有一个大问题。
我有一个使用 Google 的 Protobuf 在 C++ 上的服务器/客户端应用程序。 效果很好。
客户端将数据发送到应分发此消息的服务器 给其他客户。
C++ 客户端是一个纯粹的发送者,将 Protobuf-Struct 打包在一个固定大小(500 atm)的字符数组中。
C++ 服务器对其进行反序列化,查找命令(登录注销或给其他人的消息),然后(如果是消息)将其发送给 C#-Client。 这也是通过 500 个字符的固定大小来完成的。
这很好用。 现在在 C# 方面:
C# 客户端 atm 可以使用 Protobuf-net 登录和发送消息。即使 Protobuf-Net 将它打包成一个动态大小的字节数组(与 c++ 端的字符数组不同,它是无符号的),这也非常有效。 即便如此,服务器也会识别出消息并将其打印出来。
但是当服务器从 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++-Server 只是将 char-Array 转发给 C#-client, 这与没有序列化部分的 UDP-Client 相同。
我收到如下错误: 原型异常: 源数据中的无效字段: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-File 然后从中构建库,参考 ProtoBuf.dll 统一 然后让预编译器制作一个 Serialize.dll 以包含在 Unity3D 中
【问题讨论】:
你的问题是什么? 已更新。问题是:为什么我会收到这些错误。为什么它不起作用? :// 【参考方案1】:好的,我重新阅读你的代码更好。我认为问题可能与您处理 c# 服务器的方式有关。我认为您应该尝试这种方法:
MemoryStream 流 = new MemoryStream(incoming, false); ModelSerializer 序列化器 = new ModelSerializer(); message = (SendPack) serializer.Deserialize(stream,incoming,typeof(incoming));
【讨论】:
这给了我:InvalidCastException:无法从源类型转换为目标类型。 SendPackSerializer.Deserialize (Int32 , System.Object , ProtoBuf.ProtoReader ) 这听起来像是一个转换错误(我可能弄乱了变量),检查Derialize的签名并相应地修复变量。 已经找到解决方案。如果有人可能有同样的问题,请在此线程中发布它【参考方案2】:好的。我现在找到了答案。
如果传入的消息具有固定长度(在我的情况下为 500),如果它不是 Protobuf 的确切字节大小,那么 Protobuf-Net 就存在真正的问题。
我以这种方式修改了我的 C++-Server:
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();
【讨论】:
以上是关于C++ 中的 Google ProtoBuf 与 C# (UDP) 中的 Protobuf-net 聊天的主要内容,如果未能解决你的问题,请参考以下文章
C++ 协议缓冲区:常量表达式中的临时非文字类型 'google::protobuf::internal::CallOnInitializedMutex <std::mutex>'
由于 C++ 而解决 Google protobuf 中的枚举字段命名限制的解决方案