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 中的枚举字段命名限制的解决方案

Protobuf C++ 与 Android Java

论Protobuf在Java中的Immutability

C++ 使用 google Protobuf 2 和 protobuf3 依赖项?

C++ 中的 Google 协议缓冲区:从现有结构创建消息