Protobuf简介
ProtoBuf在网络通信、通用数据交换等场景的效率、兼容性等方面非常出色。
介绍
protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。支持 Java、C++、Python 等多种语言,支持多个平台。
你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。
特点
序列化将结构数据或对象转换成能够被存储和传输(例如网络传输)的格式,同时应当要保证这个序列化结果在之后(可能在另一个计算环境中)能够被重建回原来的结构数据或对象。可以更新数据结构,而不影响和破坏原有的旧程序
Protobuf编译
- 下载Protobuf
https://github.com/google/protobuf/releases
- 下载并安装CMake
https://cmake.org/download/
- 编译Protobuf
1、打开CMake,点击下图1 按钮选择解压出来的protobuf包位置下的cmake文件夹(xxx\protobuf-3.9.2\cmake)。
2、接着点击下图2 按钮选择编译生成目录。
3、接着点击下图3 编译
4、接着点击下图4 生成
- 产生库
使用CMake第二步选择的Vs版本软件打开编译出来的工程ALL_BUILD.vcxproj。 或直接点击CMake软件"Open Project"按钮。
如下图,只进行编译红色线框选的工程。
这里作者选择生成了x64下degbu和release:
把protobuf-3.6.1\src\google\protobuf这个目录中的头文件(其余的文件可以删除,也可以保留,不影响),都拷贝出来后面使用。
Protobuf使用
1、创建.proto文件、.bat文件
完成如上图编辑后,将protocd.exe(debug版)拷贝到同目录下,双击.bat文件运行得到.pb.cc、.pb.h两个文件。
2、 创建测试 (Vs2015+Qt5.12.4)
测试过程:创建两个Vs+Qt工程分别为A和B,使用上述proto文件定义的内容并序列化后以Udp单播在程序A和程序B中通信并显示。
(1)、创建A和B工程
(2)、创建相同的A(5566)、B(7788)程序界面
(3)、配置Protobuf
①将.pb.cc、.pb.h拷贝到代码位置并添加到工程内。②将之前编译的lib和头文件,拷贝到工程目录里面,将头文件引用、将库文件加入工程。(加入办法自行百度)
(4)、编写序列化并udp传输
// 发送端
void ProtobufTest_A::on_sendButton_A_clicked()
{
// 单播
// qint64 len = mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(),QHostAddress("192.168.137.1"),6677);
//组播ip地址范围:224.0.0.0-239.255.255.255
//qint64 len = mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(),QHostAddress("224.0.0.100"),6677);
//广播
//qint64 len = mSocket->writeDatagram(ui->textEdit->toPlainText().toUtf8(), QHostAddress::Broadcast, 6677);
// 序列化前初始值 (注意:std::string 必须转为utf8,否则异常)
tutorial::ProtobufTest protobufTest;
protobufTest.set_id(ui.port_A->text().toInt());
protobufTest.set_name(ui.ip_A->text().toUtf8().data());
protobufTest.set_email(ui.sendTxt_A->text().toUtf8().data());
// 获取长度
unsigned short protobufTestLength = protobufTest.ByteSize() + 1;
// 存储序列化buf
char *buf = nullptr;
buf = new char[protobufTestLength];
memset(buf, 0, protobufTestLength);
// 序列化
protobufTest.SerializeToArray(buf, protobufTestLength);
// udp发送(UdpSocket_A为QUdpSocket)
UdpSocket_A->writeDatagram(buf, protobufTestLength, QHostAddress(ip_B), port_B);
// 释放序列化buf
if (buf)
delete buf;
buf = nullptr;
}
// 接收端
void ProtobufTest_A::readyRead()
{
QByteArray array;
// UdpSocket_A为QUdpSocket
array.resize(UdpSocket_A->bytesAvailable());
if (array.size())
{
// 接收消息
UdpSocket_A->readDatagram(array.data(), array.size());
tutorial::ProtobufTest protobufTest;
// 反序列化
protobufTest.ParseFromArray(array.data(), array.size());
// 显示
ui.receiveTxt_A->append("id:\t" + QString::number(protobufTest.id()));
ui.receiveTxt_A->append("name:\t" + QString(protobufTest.name().c_str()));
ui.receiveTxt_A->append("email:\t" + QString(protobufTest.email().c_str()) + '\n');
}
}
(5)、查看结果
源码
关注
微信公众号搜索"Qt_io_"或"Qt开发者中心"了解更多关于Qt、C++开发知识.。
笔者 - jxd