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的库引用项目,报如下错误:
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@@@std@@@@A)
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@@@std@@@@A)
error LNK2001: 无法解析的外部符号 "int google::protobuf::internal::empty_string_once_init_" (?empty_string_once_init_@internal@protobuf@google@@3HA)
需要在工程中添加预处理PROTOBUF_USE_DLLS
Protos:
syntax = "proto3"; message CoinMsg
{ } syntax = "proto3"; message ExecMsg
{
string name = ;
} syntax = "proto3"; message VerifyMsg
{
bool isOk = ;
string error = ;
} syntax = "proto3"; import "ExecMsg.proto";
import "CoinMsg.proto";
import "VerifyMsg.proto"; message MsgPolicy
{
enum Type
{
ExecMsg = ;
CoinMsg = ;
VerifyMsg = ;
}
Type type = ;
ExecMsg execMsg = ;
CoinMsg coinMsg = ;
VerifyMsg verifyMsg = ;
}
每个Message对应一个proto文件
// 一次生成完cpp与csharp代码,注protobuf-version-3.1.0
protoc -I ./*.proto --cpp_out=../cpp --csharp_out=../csharp
使用示例:
#include "ConfigHelper.h"
#include <QFile>
#include <QDebug>
#include <QDataStream>
#include <iostream>
#include <fstream>
#include <string>
#include "MsgPolicy.pb.h"
#include <google/protobuf/message_lite.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h> ConfigHelper* ConfigHelper::instance = new ConfigHelper(); ConfigHelper::ConfigHelper()
{
#pragma region standard c++ io
{
// 序列化到文件
MsgPolicy msgPolicy;
ExecMsg* execMsg = new ExecMsg();
execMsg->set_name("exec message name.");
msgPolicy.set_allocated_execmsg(execMsg);
msgPolicy.set_type(MsgPolicy::ExecMsg);
//QFile file("msg.bin");
//file.open(QIODevice::WriteOnly);
std::fstream out("msg.bin", std::ios::out | std::ios::binary | std::ios::trunc);
msgPolicy.SerializeToOstream(&out);
out.close(); // 从文件反序列化到对象
MsgPolicy dmsgPolicy;
std::fstream in("msg.bin", std::ios::in | std::ios::binary);
if (!dmsgPolicy.ParseFromIstream(&in))
{
qDebug() << "deserialize data error.";
return;
}
if (dmsgPolicy.type() == MsgPolicy_Type::MsgPolicy_Type_CoinMsg);
else if (dmsgPolicy.type() == MsgPolicy_Type::MsgPolicy_Type_ExecMsg)
{
qDebug() << "policy message type = " << "MsgPolicy_Type::MsgPolicy_Type_ExecMsg";
qDebug() << "execMsg name = " << QString::fromStdString(dmsgPolicy.execmsg().name());
}
else if (dmsgPolicy.type() == MsgPolicy_Type::MsgPolicy_Type_VerifyMsg);
in.close();
}
#pragma endregion standard c++ io #pragma region protobuf codedstream
{
// 序列化
MsgPolicy msgPolicy5;
VerifyMsg* verifyMsg = new VerifyMsg();
verifyMsg->set_isok(false);
verifyMsg->set_error("the password is invalid.");
msgPolicy5.set_allocated_verifymsg(verifyMsg);
msgPolicy5.set_type(MsgPolicy_Type::MsgPolicy_Type_VerifyMsg);
int len = msgPolicy5.ByteSize() + ;
char* buffer = new char[len];
google::protobuf::io::ArrayOutputStream arrayOut(buffer, len);
google::protobuf::io::CodedOutputStream codedOut(&arrayOut);
codedOut.WriteVarint32(msgPolicy5.ByteSize());
if (!msgPolicy5.SerializeToCodedStream(&codedOut))
{
qDebug() << "serialize error.";
}
delete buffer; // 序列化
len = msgPolicy5.ByteSize();
buffer = new char[len];
if (!msgPolicy5.SerializeToArray(buffer, len)) qDebug() << "serialize error."; // 反序列化
MsgPolicy msgPolicy6;
msgPolicy6.ParseFromArray(buffer, len);
if (msgPolicy6.type() == MsgPolicy_Type::MsgPolicy_Type_CoinMsg);
else if (msgPolicy6.type() == MsgPolicy_Type::MsgPolicy_Type_ExecMsg);
else if (msgPolicy6.type() == MsgPolicy_Type::MsgPolicy_Type_VerifyMsg)
{
qDebug() << "policy message type = " << "MsgPolicy_Type::MsgPolicy_Type_VerifyMsg";
qDebug() << "isOk = " << msgPolicy6.verifymsg().isok() << "error = " << QString::fromStdString(msgPolicy6.verifymsg().error());
}
delete buffer;
}
#pragma endregion protobuf codedstream
google::protobuf::ShutdownProtobufLibrary();
}
// 输出结果
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中关键代码
udpHelper = new UDPHelper(this, , );
QUdpSocket *udp = udpHelper->UdpSocket();
connect(udp, &QUdpSocket::readyRead, this, [=]() {
while (udp->hasPendingDatagrams())
{
QNetworkDatagram dg = udp->receiveDatagram();
QByteArray dga = dg.data();
QString str(dga); MsgPolicy msg;
msg.ParseFromString(str.toStdString());
if (msg.type() == MsgPolicy_Type::MsgPolicy_Type_CoinMsg);
else if (msg.type() == MsgPolicy_Type::MsgPolicy_Type_ExecMsg);
else if (msg.type() == MsgPolicy_Type::MsgPolicy_Type_VerifyMsg)
{
qDebug() << "policy message type = " << "MsgPolicy_Type::MsgPolicy_Type_VerifyMsg";
qDebug() << "isOk = " << msg.verifymsg().isok() << "error = " << QString::fromStdString(msg.verifymsg().error());
}
}
});
MsgPolicy msg;
VerifyMsg *verify = new VerifyMsg();
verify->set_isok(true);
verify->set_error("from qt c++.");
msg.set_allocated_verifymsg(verify);
msg.set_type(MsgPolicy_Type::MsgPolicy_Type_VerifyMsg);
// 序列化
int len = msg.ByteSize();
char *buffer = new char[len];
if (!msg.SerializeToArray(buffer, len)) qDebug() << "serialize error.";
else udpHelper->Write(buffer, len);
2.Unity3d中关键代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Google.Protobuf;
using UnityEngine; public class UdpHelper: IDisposable
{
private UdpClient udp;
private IPEndPoint remote;
public Action<byte[]> onData; public async Task Setup(int src, int dst)
{
remote = new IPEndPoint(IPAddress.Parse("127.0.0.1"), dst);
//udp = new UdpClient(src);
udp = new UdpClient(new IPEndPoint(IPAddress.Parse("127.0.0.1"), src));
#region Windows udp 10054 error(ConnectionReset[远程主机强迫关闭一个现有连接])
// 问题详情: https://www.cnblogs.com/pasoraku/p/5612105.html
uint IOC_IN = 0x80000000;
int IOC_VENDOR = 0x18000000;
#pragma warning disable CS0675 // 对进行了带符号扩展的操作数使用了按位或运算符
int SIO_UDP_CONNRESET = (int)(IOC_IN | IOC_VENDOR | );
#pragma warning restore CS0675 // 对进行了带符号扩展的操作数使用了按位或运算符
udp.Client.IOControl(SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null);
#endregion await Listener();
} private async Task Listener()
{
try
{
UdpReceiveResult result = await udp.ReceiveAsync();
if (onData != null)
onData.Invoke(result.Buffer);
await Listener();
}
catch (ObjectDisposedException) { } // Ignore
catch (Exception e)
{
Debug.LogWarning(e.Message);
}
} public void Send(byte[] data)
{
if (udp != null)
{
udp.SendAsync(data, data.Length, remote);
}
} public void Dispose()
{
if (udp != null)
{
udp.Close();
udp = null;
}
}
}
udpHelper = new UdpHelper();
udpHelper.onData += bytes =>
{
MsgPolicy msg = MsgPolicy.Parser.ParseFrom(bytes);
if (msg.Type == MsgPolicy.Types.Type.CoinMsg) ;
else if (msg.Type == MsgPolicy.Types.Type.ExecMsg) ;
else if (msg.Type == MsgPolicy.Types.Type.VerifyMsg)
{
Debug.LogWarning("policy message type = " + "MsgPolicy_Type::MsgPolicy_Type_VerifyMsg");
Debug.LogWarning("isOk = " + msg.VerifyMsg.IsOk + " error = " + msg.VerifyMsg.Error);
}
};
await udpHelper.Setup(srcUdpPort, dstUdpPort);
MsgPolicy msg = new MsgPolicy();
msg.Type = MsgPolicy.Types.Type.VerifyMsg;
msg.VerifyMsg = new VerifyMsg(){IsOk = true, Error = "from unity3d c#"};
byte[] data = msg.ToByteArray();
udpHelper.Send(data);
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++.
Windows下编译Google.Protobuf在Qt(C++)中使用与Unity3d(C#)交互的更多相关文章
- windows下编译qt的mysql驱动
windows下编译qt的mysql驱动cd %QTDIR%\src\plugins\sqldrivers\mysqlqmake –o Makefile INCLUDEPATH+="C:\M ...
- (转)windows下编译最新的x264
二:<windows下编译最新的x264> X264更新的比较快,每天都有更新,但算法模块,基本结构是没有多大变化的.x264都是用C语言写的包括C99,但C99语法是在VC中是没法用的( ...
- Windows下编译vpx获得各个项目VS2010解决方案的步骤
最近研究了一下几种常见的视频编码器:x264,x265,vpx.本文简单记录一下它们的编译方法. x264,x265,vpx这三个开源的视频编码器可以说是当今“最火”的视频编码器.x264现在占据着H ...
- [分享]windows下编译squid的经验(转)
squid是什么我这里就不说了,这不是本文的重点,总之它是一个集:代理.加速.缓存.负载均衡.防盗链.访问控制等多功能的一个超牛X开源软件,如今已经广泛应用于很多领域.对于缓存和加速这一领域,如今各大 ...
- 在Windows下编译WebRTC
前言 这篇文章的目的在于为你节省生命中宝贵的10小时(甚至更多),或者浪费你10分钟.作为Google更新频繁的大型跨平台基础库,WebRTC的编译一直被人称为噩梦.如果恰巧你偏要在Windows下编 ...
- [转] Windows下编译OpenSSL
简述 OpenSSL是一个开源的第三方库,它实现了SSL(Secure SocketLayer)和TLS(Transport Layer Security)协议,被广泛企业应用所采用.对于一般的开发人 ...
- Windows下编译objective-C
Windows下编译objective-C 2011-08-31 14:32 630人阅读 评论(0) 收藏 举报 windowscocoa工具objective clibraryxcode 目录 ...
- 在Windows下编译FFmpeg详细说明
MinGW:一个可自由使用和自由发布的Windows特定头文件和使用GNC工具集导入库的集合,允许你生成本地的Windows程序而不需要第三方C运行时 MinGW,即 Minimalist GNU F ...
- 如何在WINDOWS下编译BOOST C++库 .
如何在WINDOWS下编译BOOST C++库 cheungmine 2008-6-25 写出来,怕自己以后忘记了,也为初学者参考.使用VC8.0和boost1.35.0. 1)下载boost ...
随机推荐
- Navicat Premium15安装与激活(破解)
Navicat premium是一款数据库管理工具,是一个可多重连线资料库的管理工具,它可以让你以单一程式同时连线到 MySQL.SQLite.Oracle 及 PostgreSQL 资料库,让管理不 ...
- Uva12716 素数筛思想的应用
Uva12716 题意: 输入整数n,1<= n <=3e7,问有多少个整数对(a,b)满足:1 <= b <= a <= n,且gcd(a,b)== a XOR b 解 ...
- Console对象与错误处理机制
console的常见用途有两个. 调试程序,显示网页代码运行时的错误信息. 提供了一个命令行接口,用来与网页代码互动. console对象的浏览器实现,包含在浏览器自带的开发工具之中.按 F12 打开 ...
- [HNOI2015]接水果[整体二分]
[HNOI2015]接水果 给出一个树上路径集合\(S\) 多次询问\(x,y\)中的\(k\)小值 如果你问我数列上那么我会 树上的话 树上差分了吧直接?- 令 \(st_x<st_y\) 1 ...
- gulp常用插件之gulp-postcss使用
更多gulp常用插件使用请访问:gulp常用插件汇总 ** gulp-postcss**这是一款通过多个插件通过管道传递CSS,但是仅解析一次CSS. 更多使用文档请点击访问gulp-postcss工 ...
- with open()函数中,如何在文件名设置中引用变量(python)
name = "wangyang" age = " with open("C:/Users/mike1/Desktop/name_age.txt", ...
- 【巨杉数据库SequoiaDB】巨杉数据库 v5.0 Beta版 正式发布
2020年疫情的出现对众多企业运营造成了严重的影响.面对突发状况,巨杉利用长期积累的远程研发协作体系,仍然坚持进行技术创新,按照已有规划推进研发工作,正式推出了巨杉数据库(SequoiaDB) v ...
- H5-当你想在出现遮罩的时候,锁住用户的滚动行为,你可以这么做。
<div class="mask"> <div class="content">我是弹框</div> </div> ...
- musql 单表查询
一 介绍 本节内容: 查询语法 关键字的执行优先级 简单查询 单条件查询:WHERE 分组查询:GROUP BY HAVING 查询排序:ORDER BY 限制查询的记录数:LIMIT 使用聚合函数查 ...
- 小白月赛22 G : 仓库地址
G : 仓库地址 考察点: 二维中位数 坑点 : 做就 OK 析题得侃: 我们发现 x 和 y 是相互独立的,也就是说先移动 x 或者先移动 y 都是可以到达一个点的,所以我们可以先找到 横坐标的 中 ...