文章目录
- 前言
- 下载安装Protocol Compiler和Protobuf Runtime
- 下载
- 编译安装Protobuf Runtime
- 使用Protocol Compiler生成.cc和.h文件
- VS工程的配置
- 测试
前言
Protobuf是一种数据交换格式,类似于Json和XML。但Portobuf序列化后的包的大小要比Json和XML小很多,解包的速度也要快很多。这就是为什么需要学Protobuf的原因,在追求通讯速度的环境下,Protobuf要优于Json和XML。但Protobuf唯一稍微麻烦的是,protobuf没有可读性,必须得借助工具来解析。 工具和版本:
- VS2019
- CMake 3.19.2
- protobuf 3.17.3
这篇教程主要是参考了官方教程来做的,英文好的同学可以自行去Protocol Buffers google 开发者网站查阅。要注意访问google网站需要科学上网。 先介绍下整个步骤:
- 下载Protocol Compiler和Protobuf Runtime
- 用CMake编译Protobuf Runtime生成libprotobufd.lib和libprotocd.lib库文件
- 编写自定义的.proto文件
- 用Protocol Compiler即protoc.exe生成.h和.cc文件
- 在VS工程中链接库文件,将google文件夹引入工程。引入生成的.h和.cc文件
下载安装Protocol Compiler和Protobuf Runtime
下载
建议英语好的同学,先阅读protobuf仓库主页 readme文件了解初步指南,再阅读protocbuf C++的安装指南 readme文件,了解不同系统的安装方法,最后阅读用CMake和MSVC编译Runtime readme文件,来完成库的生成。 第一手资料才最可靠。 先简单介绍下这两个东西。 Protocol Compiler是用来将我们自定义的.proto文件生成对应的数据结构源文件如C++的.cc和.h文件,改变输出参数也可以生成python的.py文件,java的.java文件等。
官方的语言支持有:C++ Java Python Objective-C C# Javascript Ruby Go PHP Dart。
Protobuf Runtime是用来生成库文件并且提供必要的文件,集成到你的代码里使用的。其实如果语言用的是C++的话,是不需要下载Protocol Compiler的,在编译时会生成protoc.exe来支持我们编译.proto文件。Protocol Compiler只是为了方便那些非C++语言的,这里我们还是两个都下载。
首先我们访问protobuf git仓库 releasesv3.17.3,如图,我们下载标识的两个文件(根据自己的系统的语言来),第一个就是runtime,第二个是compiler。
编译安装Protobuf Runtime
编译安装Runtime只需用到CMake和Visual Studio。 这里我用的是Developer Command Prompt for VS 2019命令行工具的,其实也可以用cmake的GUI的,参考protobuf(C++)的使用(windows)。
ps:Developer Command Prompt for VS 与CMD的命令基本相同。只是Prompt for VS和CMD的环境不同,Prompt for VS可以调用Visual studio的所有工具如msbuild,而CMD必须要设置好PATH才能调用。
首先做一些准备工作,新建一个文件夹protobuftest,将下载的Runtime压缩包解压到protobuftest文件夹内。在protobuftest文件夹新建一个install文件夹。
后面的工作全部通过敲命令完成。
第二步,从应用中找到Developer Command Prompt for VS 2019应用,打开以后先进入指定盘符,然后敲入以下命令。
该命令的作用是,在cmake文件夹里创建一个build\release文件夹,并进入该目录。
D:\VS2019>E:
E:\>cd protobuftest\protobuf-cpp-3.17.3\cmake & mkdir build & cd build & mkdir release & cd release
第三步,输入以下指令,-G 后面的参数是选择生成什么makefile,-D后面跟的都是设置的参数CMAKE_BUILD_TYPE参数是编译类型,CMAKE_INSTALL_PREFIX是安装路径,给后面namke install指令指定路径的。编译的是cmake目录。这里的^符号是换行的意思,在CMD也能这么使用。
E:\protobuftest\protobuf-cpp-3.17.3\cmake\build\release>cmake -G "NMake Makefiles" ^
-DCMAKE_BUILD_TYPE=Debug ^
-DCMAKE_INSTALL_PREFIX=../../../../install ^
../..
然后输入nmake,开始编译。编译的时候感兴趣的可以去观察release文件夹。
E:\protobuftest\protobuf-cpp-3.17.3\cmake\build\release>nmake
编译完成后,输入nmake install指令。在install之前可以输入nmake check进行test,可能出现错误,但这边先不管,只要大多数case没有错误,我们使用起来是没有问题的。
E:\protobuftest\protobuf-cpp-3.17.3\cmake\build\release>nmake install
可以观察到install文件夹已经有了以下目录。
这里的bin目录下就是protoc.exe也就是我们的Protocol Compiler工具,include目录是我们需要引用到工程的文件,lib是静态库,也需要在工程设置中链接。
使用Protocol Compiler生成.cc和.h文件
首先我们写一个简单的proto文件。
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
这里我们可以使用从git上下载下来的protoc.exe也可以用我们的install\bin目录下的protoc.exe。进入protoc.exe所在目录,按shifit+鼠标右键,选择在此处打开powershell窗口。输入以下命令:
PS E:\protobuftest\install\bin> .\protoc.exe --proto_path=.\ --cpp_out=.\ .\myproto.proto
这里proto_path指定的是.proto文件的目录,cpp_out是设置输出是用于C++的.cc和.h文件,后面跟的参数是生成文件的位置。
此时我们可以得到.cc和.h文件。
VS工程的配置
因为我们编译的是Debug的库,所以配置要选择Debug,平台要选择Win32平台。
- 配置 C/C++ 常规 附加包含目录,设置include的文件目录
- 配置 链接器 常规 附加库目录,设置lib文件目录
- 配置 链接器 输入 附加依赖项,将三个lib文件填进去libprotobufd.lib;libprotobuf-lited.lib;libprotocd.lib
ps:debug的库带d,release的库不带。
- 最后设置 高级高级属性MFC的使用,改成在静态库中使用MFC
MFC:Microsoft Foundation Class 微软基础类库
测试
使用如下代码进行测试
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <fstream>
#include "myproto.pb.h"
using namespace std;
int main()
{
//std::cout << "Hello World!\n";
SearchRequest data;
data.set_query("yy");
data.set_page_number(10);
data.set_result_per_page(12);
cout <<"origin data: "<< data.query() << "," << data.page_number() << "," << data.result_per_page()<<endl;
fstream output("./log", ios::out | ios::trunc | ios::binary);
//此处是执行序列化的操作,该方法执行完后,对应生成的二进制文件就保存在log文件中
if (!data.SerializeToOstream(&output))
{
cerr << "failed to write msg." << endl;
return -1;
}
getchar();
if (output.is_open())
{
output.close();
}
SearchRequest parsedata;
fstream input("./log", ios::in | ios::binary);
//此处是执行反序列化的操作
if (!parsedata.ParseFromIstream(&input))
{
cerr << "failed to parse message." << endl;
return -1;
}
cout <<"after serialization and parse: "<< parsedata.query() << "," << parsedata.page_number() << "," << parsedata.result_per_page()<<endl;
return 0;
}
工程我已经上传了,包括编译好的install文件夹,需要修改一下库和包含的路径才能使用,参考上文。资源链接 测试代码的作用是,将信息序列化后,存到工程目录的log文件下,然后在通过读取log文件,反序列化得到信息。
输出结果如下: