Windows下编译Google.Protobuf在Qt(C++)中使用与Unity3d(C#)交互
阅读原文时间:2021年04月20日阅读:3

1.首先从Github-Protobuf下载代码,本文下载的版本号是3.1.0.

2.仔细查看各个README,有相关的资源下载和编译说明.

3.在一个方便的地方创建一个Install类型的文件夹,放置Cmake生成的工程文件相关内容,使用CMake-gui配置,生成visual studio ide工程.

CMAKE_CONFIGRATION_TYPES是工程配置类型,可以删除不感兴趣的配置.

CMAKE_INSTALL_PREFIX是导出visual studio ide项目文件的位置

根据自己的需求选择BUILD_SHARED_LIBS或者是MSVC_STATIC_RUNTIME(对应编译选项/Mtd和/Mt),二者选其一

4.Open Project直接编译工程.


将生成的protobuf的库引用项目,报如下错误:

1 error LNK2001: 无法解析的外部符号 "class google::protobuf::internal::ExplicitlyConstructed,class std::allocator > > google::protobuf::internal::fixed_address_empty_string" (?fixed_address_empty_string@internal@protobuf@google@@3V?$ExplicitlyConstructed@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@123@A) 2 error LNK2001: 无法解析的外部符号 "class google::protobuf::internal::ExplicitlyConstructed,class std::allocator > > google::protobuf::internal::fixed_address_empty_string" (?fixed_address_empty_string@internal@protobuf@google@@3V?$ExplicitlyConstructed@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@123@A) 3 error LNK2001: 无法解析的外部符号 "int google::protobuf::internal::empty_string_once_init_" (?empty_string_once_init_@internal@protobuf@google@@3HA)

需要在工程中添加预处理PROTOBUF_USE_DLLS


Protos:

1 syntax = "proto3";
2
3 message CoinMsg
4 {
5
6 }
7
8 syntax = "proto3";
9
10 message ExecMsg 11 { 12 string name = 1; 13 } 14
15 syntax = "proto3"; 16
17 message VerifyMsg 18 { 19 bool isOk = 1; 20 string error = 2; 21 } 22
23 syntax = "proto3"; 24
25 import "ExecMsg.proto"; 26 import "CoinMsg.proto"; 27 import "VerifyMsg.proto"; 28
29 message MsgPolicy 30 { 31 enum Type 32 { 33 ExecMsg = 0; 34 CoinMsg = 1; 35 VerifyMsg = 2; 36 } 37 Type type = 1; 38 ExecMsg execMsg = 2; 39 CoinMsg coinMsg = 3; 40 VerifyMsg verifyMsg = 4; 41 }

View Code

  每个Message对应一个proto文件  

// 一次生成完cpp与csharp代码,注protobuf-version-3.1.0
protoc -I ./*.proto --cpp_out=../cpp --csharp_out=../csharp

使用示例:

1 #include "ConfigHelper.h"
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include 8 #include "MsgPolicy.pb.h" 9 #include
10 #include
11 #include
12
13 ConfigHelper* ConfigHelper::instance = new ConfigHelper(); 14
15 ConfigHelper::ConfigHelper() 16 { 17 #pragma region standard c++ io
18 { 19 // 序列化到文件
20 MsgPolicy msgPolicy; 21 ExecMsg* execMsg = new ExecMsg(); 22 execMsg->set_name("exec message name."); 23 msgPolicy.set_allocated_execmsg(execMsg); 24 msgPolicy.set_type(MsgPolicy::ExecMsg); 25 //QFile file("msg.bin"); 26 //file.open(QIODevice::WriteOnly);
27 std::fstream out("msg.bin", std::ios::out | std::ios::binary | std::ios::trunc); 28 msgPolicy.SerializeToOstream(&out); 29 out.close(); 30
31 // 从文件反序列化到对象
32 MsgPolicy dmsgPolicy; 33 std::fstream in("msg.bin", std::ios::in | std::ios::binary); 34 if (!dmsgPolicy.ParseFromIstream(&in)) 35 { 36 qDebug() << "deserialize data error."; 37 return; 38 } 39 if (dmsgPolicy.type() == MsgPolicy_Type::MsgPolicy_Type_CoinMsg); 40 else if (dmsgPolicy.type() == MsgPolicy_Type::MsgPolicy_Type_ExecMsg) 41 { 42 qDebug() << "policy message type = " << "MsgPolicy_Type::MsgPolicy_Type_ExecMsg"; 43 qDebug() << "execMsg name = " << QString::fromStdString(dmsgPolicy.execmsg().name()); 44 } 45 else if (dmsgPolicy.type() == MsgPolicy_Type::MsgPolicy_Type_VerifyMsg); 46 in.close(); 47 } 48 #pragma endregion standard c++ io 49 50 #pragma region protobuf codedstream 51 { 52 // 序列化 53 MsgPolicy msgPolicy5; 54 VerifyMsg* verifyMsg = new VerifyMsg(); 55 verifyMsg->set_isok(false); 56 verifyMsg->set_error("the password is invalid."); 57 msgPolicy5.set_allocated_verifymsg(verifyMsg); 58 msgPolicy5.set_type(MsgPolicy_Type::MsgPolicy_Type_VerifyMsg); 59 int len = msgPolicy5.ByteSize() + 4; 60 char* buffer = new char[len]; 61 google::protobuf::io::ArrayOutputStream arrayOut(buffer, len); 62 google::protobuf::io::CodedOutputStream codedOut(&arrayOut); 63 codedOut.WriteVarint32(msgPolicy5.ByteSize()); 64 if (!msgPolicy5.SerializeToCodedStream(&codedOut)) 65 { 66 qDebug() << "serialize error."; 67 } 68 delete buffer; 69
70 // 序列化
71 len = msgPolicy5.ByteSize(); 72 buffer = new char[len]; 73 if (!msgPolicy5.SerializeToArray(buffer, len)) qDebug() << "serialize error."; 74
75 // 反序列化
76 MsgPolicy msgPolicy6; 77 msgPolicy6.ParseFromArray(buffer, len); 78 if (msgPolicy6.type() == MsgPolicy_Type::MsgPolicy_Type_CoinMsg); 79 else if (msgPolicy6.type() == MsgPolicy_Type::MsgPolicy_Type_ExecMsg); 80 else if (msgPolicy6.type() == MsgPolicy_Type::MsgPolicy_Type_VerifyMsg) 81 { 82 qDebug() << "policy message type = " << "MsgPolicy_Type::MsgPolicy_Type_VerifyMsg"; 83 qDebug() << "isOk = " << msgPolicy6.verifymsg().isok() << "error = " << QString::fromStdString(msgPolicy6.verifymsg().error()); 84 } 85 delete buffer; 86 } 87 #pragma endregion protobuf codedstream
88 google::protobuf::ShutdownProtobufLibrary(); 89 }

View Code

// 输出结果
policy message type = MsgPolicy_Type::MsgPolicy_Type_ExecMsg
execMsg name = "exec message name." policy message type = MsgPolicy_Type::MsgPolicy_Type_VerifyMsg
isOk = false error = "the password is invalid."

下面展示与unity3d 2017.2使用Google.Protobuf的数据通信(Google.Protobuf --Version 3.1.0)


1.Qt中关键代码

1 udpHelper = new UDPHelper(this, 8920, 8921);
2 QUdpSocket *udp = udpHelper->UdpSocket();
3 connect(udp, &QUdpSocket::readyRead, this, [=]() {
4 while (udp->hasPendingDatagrams())
5 {
6 QNetworkDatagram dg = udp->receiveDatagram();
7 QByteArray dga = dg.data(); 8 QString str(dga);
9
10 MsgPolicy msg; 11 msg.ParseFromString(str.toStdString()); 12 if (msg.type() == MsgPolicy_Type::MsgPolicy_Type_CoinMsg); 13 else if (msg.type() == MsgPolicy_Type::MsgPolicy_Type_ExecMsg); 14 else if (msg.type() == MsgPolicy_Type::MsgPolicy_Type_VerifyMsg) 15 { 16 qDebug() << "policy message type = " << "MsgPolicy_Type::MsgPolicy_Type_VerifyMsg"; 17 qDebug() << "isOk = " << msg.verifymsg().isok() << "error = " << QString::fromStdString(msg.verifymsg().error()); 18 } 19 } 20 });

View Code

1 MsgPolicy msg;
2 VerifyMsg *verify = new VerifyMsg(); 3 verify->set_isok(true);
4 verify->set_error("from qt c++.");
5 msg.set_allocated_verifymsg(verify);
6 msg.set_type(MsgPolicy_Type::MsgPolicy_Type_VerifyMsg);
7 // 序列化
8 int len = msg.ByteSize(); 9 char *buffer = new char[len]; 10 if (!msg.SerializeToArray(buffer, len)) qDebug() << "serialize error."; 11 else udpHelper->Write(buffer, len);

View Code

2.Unity3d中关键代码

1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Net; 5 using System.Net.Sockets; 6 using System.Text; 7 using System.Threading.Tasks; 8 using Google.Protobuf; 9 using UnityEngine; 10
11 public class UdpHelper: IDisposable 12 { 13 private UdpClient udp; 14 private IPEndPoint remote; 15 public Action onData; 16
17 public async Task Setup(int src, int dst) 18 { 19 remote = new IPEndPoint(IPAddress.Parse("127.0.0.1"), dst); 20 //udp = new UdpClient(src);
21 udp = new UdpClient(new IPEndPoint(IPAddress.Parse("127.0.0.1"), src)); 22 #region Windows udp 10054 error(ConnectionReset[远程主机强迫关闭一个现有连接])
23 // 问题详情: https://www.cnblogs.com/pasoraku/p/5612105.html
24 uint IOC_IN = 0x80000000; 25 int IOC_VENDOR = 0x18000000; 26 #pragma warning disable CS0675 // 对进行了带符号扩展的操作数使用了按位或运算符
27 int SIO_UDP_CONNRESET = (int)(IOC_IN | IOC_VENDOR | 12); 28 #pragma warning restore CS0675 // 对进行了带符号扩展的操作数使用了按位或运算符
29 udp.Client.IOControl(SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null); 30 #endregion
31
32 await Listener(); 33 } 34
35 private async Task Listener() 36 { 37 try
38 { 39 UdpReceiveResult result = await udp.ReceiveAsync(); 40 if (onData != null) 41 onData.Invoke(result.Buffer); 42 await Listener(); 43 } 44 catch (ObjectDisposedException) { } // Ignore
45 catch (Exception e) 46 { 47 Debug.LogWarning(e.Message); 48 } 49 } 50
51 public void Send(byte[] data) 52 { 53 if (udp != null) 54 { 55 udp.SendAsync(data, data.Length, remote); 56 } 57 } 58
59 public void Dispose() 60 { 61 if (udp != null) 62 { 63 udp.Close(); 64 udp = null; 65 } 66 } 67 }

View Code

1 udpHelper = new UdpHelper(); 2 udpHelper.onData += bytes =>
3 {
4 MsgPolicy msg = MsgPolicy.Parser.ParseFrom(bytes); 5 if (msg.Type == MsgPolicy.Types.Type.CoinMsg) ; 6 else if (msg.Type == MsgPolicy.Types.Type.ExecMsg) ; 7 else if (msg.Type == MsgPolicy.Types.Type.VerifyMsg) 8 {
9 Debug.LogWarning("policy message type = " + "MsgPolicy_Type::MsgPolicy_Type_VerifyMsg"); 10 Debug.LogWarning("isOk = " + msg.VerifyMsg.IsOk + " error = " + msg.VerifyMsg.Error); 11 } 12 }; 13 await udpHelper.Setup(srcUdpPort, dstUdpPort);

View Code

1 MsgPolicy msg = new MsgPolicy(); 2 msg.Type = MsgPolicy.Types.Type.VerifyMsg; 3 msg.VerifyMsg = new VerifyMsg(){IsOk = true, Error = "from unity3d c#"}; 4 byte[] data = msg.ToByteArray(); 5 udpHelper.Send(data);

View Code

3.程序输出

// In Qt
policy message type =  MsgPolicy_Type::MsgPolicy_Type_VerifyMsg
isOk =  true error =  "from unity3d c#"
// In Unity3d
policy message type = MsgPolicy_Type::MsgPolicy_Type_VerifyMsg
isOk = True error = from qt c++.

Google.Protobuf3语言指南

转载于:https://www.cnblogs.com/linxmouse/p/8975475.html

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章