文章目录
- 参考
- 前言
- 开发环境
- # 一、下载
- 1. 打开网页
- 2. 点击download
- 3. 下载
- 二、 编译
- 1. 解压
- 2. 用QC打开项目
- 3. 编译并等待
- 4. 打开 `extract_includes.bat`
- 5. 新建lib文件夹
- 三、使用
- 1. 新建 lm.helloworld.proto
- 2. Qt 新建 HelloProtobuf 子目录项目
- 3. lib_protobuf 目录
- 4. Writer 工程
- 5. Reader 工程
- 四、总结
参考
Protobuf通信协议详解:代码演示、详细原理介绍等 - 知乎 (zhihu.com)
Protocol Buffers | Google Developers
前言
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
看到有人说起protobuf这个数据交换的格式,和平台无关,和语言无关,性能还比较好,就想学习一下。想到就做,边做边记录。
开发环境
- win10
- Qt 5.15.2
- msvc2019 x64
# 一、下载
1. 打开网页
https://developers.google.cn/protocol-buffers/
2. 点击download
3. 下载
二、 编译
1. 解压
目录结构如下
protobuf-3.21.9
├─benchmarks
├─build_defs
├─cmake
├─conformance
├─csharp
├─editors
├─examples
├─m4
├─objectivec
├─php
├─ruby
├─src
├─third_party
└─util
2. 用QC打开项目
3. 编译并等待
编译结果如下:
..\protobuf-3.21.9\build-cmake-Desktop_Qt_5_15_2_MSVC2019_64bit-Release
│ .ninja_deps
│ .ninja_log
│ build.ninja
│ CMakeCache.txt
│ cmake_install.cmake
│ CTestTestfile.cmake
│ extract_includes.bat // <------------ 注意这个文件
│ gmock.lib
│ gmock_main.lib
│ libprotobuf-lite.lib
│ libprotobuf.lib
│ libprotoc.lib
│ lite-arena-test.exe
│ lite-arena-test.exe.manifest
│ lite-test.exe
│ lite-test.exe.manifest
│ protobuf-lite-test-common.lib
│ protobuf-lite.pc
│ protobuf-test-common.lib
│ protobuf.pc
│ protoc.exe
│ protoc.exe.manifest
│ qtcsettings.cmake
│ tests.exe
│ tests.exe.manifest
│ test_plugin.exe
│ test_plugin.exe.manifest
│ version.rc
│
├─.cmake
├─.qtc_clangd
├─cmake
├─CMakeFiles
└─Testing
4. 打开 extract_includes.bat
内容如下所示:
# 新建一批目录
mkdir include
mkdir include\google
mkdir include\google\protobuf
mkdir include\google\protobuf\compiler
......
# 复制头文件到对应目录最终
copy "E:\3rd\protobuf-3.21.9\..\src\google\protobuf\any.h" include\google\protobuf\any.h
copy "E:\3rd\protobuf-3.21.9\..\src\google\protobuf\any.pb.h" include\google\protobuf\any.pb.h
copy "E:\3rd\protobuf-3.21.9\..\src\google\protobuf\api.pb.h" include\google\protobuf\api.pb.h
.....
copy的路径对于我来说,有点问题,所以做相应修改,去掉中间的 \..
目录:
copy "E:\3rd\protobuf-3.21.9\src\google\protobuf\api.pb.h" include\google\protobuf\api.pb.h
执行批处理文件后,最终结果会把相应的头文件复制到include目录下
5. 新建lib文件夹
再将编译好的lib文件,复制到这个目录,可以再细分为 debug 和 release 目录(此处略),最后将 include 和 该lib文件加复制到另外一个目录:lib_protobuf
..\lib_protobuf
│ protoc.exe // 可以考虑将这个文件复制过来
├─include
│ └─google
│ └─protobuf
│ │ any.h
│ │ .........
│ ├─compiler
│ │ ├─cpp
│ │ ├─csharp
│ │ ├─java
│ │ ├─objectivec
│ │ ├─php
│ │ ├─python
│ │ └─ruby
│ ├─io
│ ├─stubs
│ └─util
└─libgmock.libgmock_main.liblibprotobuf-lite.liblibprotobuf.liblibprotoc.libprotobuf-lite-test-common.libprotobuf-test-common.lib
三、使用
protobuf的使用和qSoap的使用有点相似。
protobuf协议利用生成工具 protoc.exe 从 自定义的 .proto 的文件 生成相应语言(cpp,c#, java)的接口文件,然后加入工程进行编译即可。
命令格式:
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto
1. 新建 lm.helloworld.proto
syntax = "proto3";
package lm;
message helloworld
{int32 id = 1;string greeting = 2;
}
利用 cmd 执行 protoc.exe --cpp_out=. lm.helloworld.proto
命令即可:
- lm.helloworld.pb.h ---- 生成类的头文件
- lm.helloworld.pb.cc ---- 生成类的实现文件
2. Qt 新建 HelloProtobuf 子目录项目
再建两个子项目分别为:Reader 和 Writer,再复制 lib_protobuf 的文件夹过来
整体目录如下:
3. lib_protobuf 目录
-
将 自定义的proto文件和生成的类文件拷贝到lib_protobuf 目录下
-
新建 protobuf.pri 文件
win32: LIBS += -L$$PWD/lib/ -llibprotobufINCLUDEPATH += $$PWD/include \$$PWD DEPENDPATH += $$PWD/include# 下面这一段 可以不用 #PRE_TARGETDEPS += $$PWD/lib/libprotobuf.lib #PRE_TARGETDEPS += $$PWD/gmock.lib #PRE_TARGETDEPS += $$PWD/libprotoc.lib #PRE_TARGETDEPS += $$PWD/gmock_main.lib #PRE_TARGETDEPS += $$PWD/libprotobuf.lib #PRE_TARGETDEPS += $$PWD/libprotobuf-lite.lib #PRE_TARGETDEPS += $$PWD/protobuf-test-common.lib #PRE_TARGETDEPS += $$PWD/protobuf-lite-test-common.libHEADERS += \$$PWD/ProtobufTool.h \ // 后加的文件$$PWD/lm.helloworld.pb.h // protobuf 生成的头文件SOURCES += \$$PWD/lm.helloworld.pb.cc // protobuf 生成的实现文件DISTFILES += \$$PWD/lm.helloworld.proto \ // .proto 相当于原型文件, 加到项目中看得比较清楚$$PWD/protoc.bat // 就是一句:protoc.exe --cpp_out=. lm.helloworld.proto,方便操作
-
ProtobufTool.h
唯一的功能是序列化成 QByteArray
#ifndef PROTOBUFTOOL_H #define PROTOBUFTOOL_H //#include <google/protobuf/io/coded_stream.h> //#include <google/protobuf/arena.h> //#include <google/protobuf/arenastring.h> //#include <google/protobuf/generated_message_util.h> //#include <google/protobuf/metadata_lite.h> //#include <google/protobuf/generated_message_reflection.h> //#include <google/protobuf/repeated_field.h> // IWYU pragma: export //#include <google/protobuf/extension_set.h> // IWYU pragma: export //#include <google/protobuf/unknown_field_set.h> #include <google/protobuf/message.h> #include <google/protobuf/port_def.inc> #include <QByteArray> #include <QString>class ProtobufTool { public:static QByteArray SerializeToByteArray(PROTOBUF_NAMESPACE_ID::Message &msg){auto stdstring = msg.SerializeAsString();return QByteArray::fromStdString (stdstring);} };#endif // PROTOBUFTOOL_H
4. Writer 工程
-
Writer.pro 文件
CONFIG -= app_bundle CONFIG += c++17 SOURCES += main.cpp include ($$PWD/../lib_protobuf/protobuf.pri) msvc : QMAKE_CXXFLAGS += /utf-8
-
main.cpp
#include "ProtobufTool.h" #include "lm.helloworld.pb.h" #include <QDebug> #include <QFile> #include <QFileInfo> #define qout if( 1 ) qDebug() << __FILE__ << __LINE__ << ": "int main() {lm::helloworld msg1;msg1.set_id(1);msg1.set_greeting ("中国人民共和国!");auto ba = ProtobufTool::SerializeToByteArray(msg1);qout << ba;QFile file("../log");QFileInfo info(file);qout << info.absoluteFilePath ();if(file.open (QFile::WriteOnly)){file.write (ba);file.close ();}return 0; }
5. Reader 工程
-
Reader.pro 文件 两个工程文件是一样的
CONFIG -= app_bundle CONFIG += c++17 SOURCES += main.cpp include ($$PWD/../lib_protobuf/protobuf.pri) msvc : QMAKE_CXXFLAGS += /utf-8
-
main.cpp
#include "lm.helloworld.pb.h" #include <QFile> #include <QDebug> #define qout if( 1 ) qDebug() << __FILE__ << __LINE__ << ": "int main(void ) {lm::helloworld msg;QByteArray ba;QFile file("../log");if(file.open (QFile::ReadOnly)) {ba = file.readAll ();file.close ();}msg.ParseFromArray (ba.constData (),ba.size ());qout << msg.id ();qout << QString::fromStdString (msg.greeting());return 0; }
-
运行结果:
..\..\HelloProtobuf\Reader\main.cpp 19 : 1 ..\..\HelloProtobuf\Reader\main.cpp 20 : "中国人民共和国!"
四、总结
Protobuf 生成的对象流是二进制的,体积小巧,传输效率高。
开发效率没有json方便,如果不需要编译的程序,使用起来会更方便。
原来还想学习下protobuf的原型文件的语法来着,感觉在开发中不会用到protobuf,略吧。