Windows下编译Google.Protobuf在Qt(C++)中使用与Unity3d(C#)交互

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::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > 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::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > 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 <QFile>
 3 #include <QDebug>
 4 #include <QDataStream>
 5 #include <iostream>
 6 #include <fstream>
 7 #include <string>
 8 #include "MsgPolicy.pb.h"
 9 #include <google/protobuf/message_lite.h>
10 #include <google/protobuf/io/coded_stream.h>
11 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
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<byte[]> 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