zoukankan      html  css  js  c++  java
  • 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语言指南

  • 相关阅读:
    我心中的核心组件(可插拔的AOP)~第十三回 实现AOP的拦截组件Unity.Interception
    .NET 使用unity实现依赖注入
    AOP技术基础
    PowerShell 远程管理之 about_Remote_Troubleshooting
    PowerShell远程连接主机进行会话
    PowerShell_零基础自学课程_9_高级主题:静态类和类的操作
    PowerShell_零基础自学课程_8_高级主题:WMI对象和COM组件
    PowerShell 中的目录文件管理
    解决360浏览器兼容模式不兼容,极速模式兼容问题
    reportng之测试报告升级美化
  • 原文地址:https://www.cnblogs.com/linxmouse/p/8975475.html
Copyright © 2011-2022 走看看