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 ...
随机推荐
- 洛谷题解 P1744 【采购特价商品】
原题传送门 题目描述 中山路店山店海,成了购物狂爱与愁大神的"不归之路".中山路上有n(n<=100)家店,每家店的坐标均在-10000~10000之间.其中的m家店之间有通 ...
- NodeJS_0001:关于install的方式
最近在写Node程序的时候,突然对 npm install 的-save和-save-dev 这两个参数的使用比较混乱.其实博主在这之前对这两个参数的理解也是模糊的,各种查资料和实践后对它们之间的异同 ...
- MY_0003:设置界面显示单位
1,设置单位
- JS Radio结合TEXT
<script> function fun_a(value){ if(value === "on"){ document.getElementById('a').dis ...
- linq to sql 获取sql与参数添加到日志中
这里的linq to sql并未使用ef 主要有以下内容 1.新增 2.修改 3.删除 4.查询 1.新增,修改,删除获取sql语句通过DataContext.Log获取执行的sql语句 String ...
- [Python机器学习]机器学习概述
1.为何选择机器学习 在智能应用的早期,许多系统使用人为的if和else语句来处理数据,以主动拦截邮箱的垃圾邮件为例,可以创建一个关键词黑名单,所有包含这些关键词的邮件被标记为垃圾邮件,这是人为制定策 ...
- linux学习之编译-链接
在Windows下使用习惯了IDE,导致我们对程序的编译链接没有一个清晰的认识,甚至混淆了编辑器和编译器的概念.在学习Linux时,这些问题就暴露出来了. 实际上,我们应该严格区分一个程序从产生到执行 ...
- ubuntu 16.04.1上安装并使用vsftpd
1.安装vsftpd软件 sudo apt-get install vsftpd 2.新建文件 sudo vim /etc/vsftpd.user_list 用于记录用户名 3. 修改sudo vim ...
- 【巨杉数据库SequoiaDB】助力金融科技升级,巨杉数据库闪耀金融展
11月4日,以“科技助创新 开放促改革 发展惠民生”为主题的2019中国国际金融展和深圳国际金融博览会在深圳会展中心盛大开幕. 中国人民银行党委委员.副行长范一飞,深圳市人民政府副市长.党组成员艾学峰 ...
- CentOS 安装后的常用配置
镜像配置 CentOS系统的镜像配置文件路径在 /etc/yum.repos.d/CentOS-Base.repo, 将镜像内容copy到 CentOS-Base.repo中 然后运行 yum mak ...