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++.