Ubuntu下使用protoBuf
一、protobuf简介:
1.1 protobuf的定义:
protobuf是用来干嘛的?
protobuf是一种用于 对结构数据进行序列化的工具,从而实现 数据存储和交换。
(主要用于网络通信中 收发两端进行消息交互。所谓的“结构数据”是指类似于struct结构体的数据,可用于表示一个网络消息。当结构体中存在函数指针类型时,直接对其存储或传输相当于是“浅拷贝”,而对其序列化后则是“深拷贝”。)
**序列化:**将结构数据或者对象转换成能够用于存储和传输的格式。
**反序列化:**在其他的计算环境中,将序列化后的数据还原为数据结构和对象。
从“序列化”字面上的理解,似乎使用C语言中的struct结构体就可以实现序列化的功能:将结构数据填充到定义好的结构体中的对应字段即可,接收方再对结构体进行解析。
在单机的不同进程间通信时,使用struct结构体这种方法实现“序列化”和“反序列化”的功能问题不大,但是,在网络编程中,即面向网络中不同主机间的通信时,则不能使用struct结构体,原因在于:
(1)跨语言平台,例如发送方是用C语言编写的程序,接收方是用Java语言编写的程序,不同语言的struct结构体定义方式不同,不能直接解析;
(2)struct结构体存在内存对齐和 CPU不兼容的问题。
因此,在网络编程中,实现“序列化”和“反序列化”功能需要使用通用的组件,如 Json、XML、protobuf 等。
1.2 protobuf的优缺点:
1.2.1 优点:
① 性能高效:
与XML相比,protobuf更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。
**② 语言无关、平台无关:
**protobuf支持Java、C++、Python等多种语言,支持多个平台。
**③ 扩展性、兼容性强:
**只需要使用protobuf对结构数据进行一次描述,即可从各种数据流中读取结构数据,更新数据结构时不会破坏原有的程序。
Protobuf与XML、Json的性能对比:
测试10万次序列化:

测试10万次反序列化:

1.2.2 缺点:
① 自解释性较差,数据存储格式为二进制,需要通过 .proto 文件才能了解到内部的数据结构;
② 不适合用来对 基于文本的标记文档(如HTML) 建模。
1.3 protobuf中的数据类型限定修饰符:
protobuf 2 中有三种数据类型限定修饰符:
required, optional, repeated
required表示字段必选,optional表示字段可选,repeated表示一个数组类型。
其中, required 和 optional 已在 proto3 弃用了。
1.4 protobuf中常用的数据类型:
bool, 布尔类型double, 64位浮点数
float, 32位浮点数int32, 32位整数
int64, 64位整数
uint64, 64位无符号整数
sint32, 32位整数,处理负数效率更高
sint64, 64位整数,处理负数效率更高string, 只能处理ASCII字符
bytes, 用于处理多字节的语言字符
enum, 枚举类型
二、protobuf下载与安装
GitHub 地址:
https://github.com/protocolbuffers/protobuf
官方文档地址:
https://developers.google.com/protocol-buffers/
Releases 下载地址:
https://github.com/protocolbuffers/protobuf/releases
另外往下可以看到分平台的文件:

这些是已经 build 好的 Protocol Compiler,可以直接下载了用,也可以自己下载前面源码文件后自己进行 build
自己下载需要的版本protobuf进行编译,成功后会编译出动态库so和protoc编译器(这个也可在以上网址进行下载需要的版本 )
执行protoc编译器,成功后会有如下提示:
[root@linux] protoc --version
libprotoc 3.15.8
三、protobuf的使用流程
1.1 定义.proto文件
使用protobuf时,需要先根据应用需求编写 .proto 文件 定义消息体格式,例如:
test.proto文件如下:
syntax = "proto3";
package tutorial;option optimize_for = LITE_RUNTIME;message Person {int32 id = 1;repeated string name = 2;
}
以–cpp_out上
1、syntax 关键字表示使用的protobuf的版本,如不指定则默认使用 “proto2”
2、package关键字 表示“包”,生成目标语言文件后对应C++中的namespace命名空间,用于防止不同的消息类型间的命名冲突
3、message对应C++中的类, 内部包含各种属性, 其中repeated修饰数据类型表示是一个数组的概念
1.2 .proto文件编译
通过protoc编译器把.protoc文件编译出xxxx.pb.cc和xxxxx.pb.h
格式如下:
[root@linux] protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto
其中:
$SRC_DIR表示 .proto文件所在的源目录;
–cpp_out=$DST_DIR表示生成目标语言C++代码的目标目录;
xxx.proto表示要对哪个.proto文件进行解析;
以上目录最好使用绝对路径
编译出xxx.pb.cc和xxx.pb.h文件后,使用的话只需要把文件编译进去并链接protobuf动态库即可
类似这种格式:
g++ main_test.cpp xxx.pb.cc -o main_test -lprotobuf
1.3 C++使用protobuf实现序列化的示例
在protobuf源码中的 /examples 目录下有官方提供的protobuf使用示例:addressbook.proto
参考官方示例实现C++使用protobuf进行序列化和反序列化:
addressbook.proto :
syntax = "proto3";
package tutorial;option optimize_for = LITE_RUNTIME;message Person {string name = 1;int32 id = 2;string email = 3;enum PhoneType {MOBILE = 0;HOME = 1;WORK = 2;}message PhoneNumber {string number = 1;PhoneType type = 2;}repeated PhoneNumber phones = 4;
}
生成的addressbook.pb.h 文件内容摘要:
namespace tutorial {class Person;class Person_PhoneNumber;
};class Person_PhoneNumber : public MessageLite {
public:Person_PhoneNumber();virtual ~Person_PhoneNumber();
public://string number = 1;void clear_number();const string& number() const;void set_number(const string& value);//int32 id = 2;void clear_id();int32 id() const;void set_id(int32 value);//string email = 3; //...
};
add_person.cpp :
#include <iostream>
#include <fstream>
#include <string>
#include "pbs/addressbook.pb.h"
using namespace std;void serialize_process() {cout << "serialize_process" << endl;tutorial::Person person;person.set_name("Obama");person.set_id(1234);person.set_email("1234@qq.com");tutorial::Person::PhoneNumber *phone1 = person.add_phones();phone1->set_number("110");phone1->set_type(tutorial::Person::MOBILE);tutorial::Person::PhoneNumber *phone2 = person.add_phones();phone2->set_number("119");phone2->set_type(tutorial::Person::HOME);fstream output("person_file", ios::out | ios::trunc | ios::binary);if( !person.SerializeToOstream(&output) ) {cout << "Fail to SerializeToOstream." << endl;}cout << "person.ByteSizeLong() : " << person.ByteSizLong() << endl;
}void parse_process() {cout << "parse_process" << endl;tutorial::Person result;fstream input("person_file", ios::in | ios::binary);if(!result.ParseFromIstream(&input)) {cout << "Fail to ParseFromIstream." << endl;}cout << result.name() << endl;cout << result.id() << endl;cout << result.email() << endl;for(int i = 0; i < result.phones_size(); ++i) {const tutorial::Person::PhoneNumber &person_phone = result.phones(i);switch(person_phone.type()) {case tutorial::Person::MOBILE :cout << "MOBILE phone : ";break;case tutorial::Person::HOME :cout << "HOME phone : ";break;case tutorial::Person::WORK :cout << "WORK phone : ";break;default:cout << "phone type err." << endl;}cout << person_phone.number() << endl;}
}int main(int argc, char *argv[]) {serialize_process();parse_process();google::protobuf::ShutdownProtobufLibrary(); //删除所有已分配的内存(Protobuf使用的堆内存)return 0;
}
输出结果:
[serialize_process]
person.ByteSizeLong() : 39
[parse_process]
Obama
1234
1234@qq.com
MOBILE phone : 110
HOME phone : 119
分析
protobuf提供的序列化和反序列化的API接口函数:
class MessageLite {
public://序列化:bool SerializeToOstream(ostream* output) const;bool SerializeToArray(void *data, int size) const;bool SerializeToString(string* output) const;//反序列化:bool ParseFromIstream(istream* input);bool ParseFromArray(const void* data, int size);bool ParseFromString(const string& data);
};
三种序列化的方法没有本质上的区别,只是序列化后输出的格式不同,可以供不同的应用场景使用。
序列化的API函数均为const成员函数,因为序列化不会改变类对象的内容, 而是将序列化的结果保存到函数入参指定的地址中。
四、拓展: .proto文件中的 option 选项:
.proto文件中的option选项用于配置protobuf编译后生成目标语言文件中的代码量,可设置为 SPEED, CODE_SIZE, LITE_RUNTIME 三种。
默认option选项为 SPEED,常用的选项为 LITE_RUNTIME。
三者的区别在于:
① SPEED(默认值):
表示生成的代码运行效率高,但是由此生成的代码编译后会占用更多的空间。
② CODE_SIZE:
与SPEED恰恰相反,代码运行效率较低,但是由此生成的代码编译后会占用更少的空间,通常用于资源有限的平台,如Mobile。
③ LITE_RUNTIME:
生成的代码执行效率高,同时生成代码编译后的所占用的空间也非常少。
这是以牺牲Protobuf提供的反射功能为代价的。
因此我们在C++中链接Protobuf库时仅需链接libprotobuf-lite,而非protobuf。
SPEED 和 LITE_RUNTIME相比,在于调试级别上,例如 msg.SerializeToString(&str); 在 SPEED 模式下会利用反射机制打印出详细字段和字段值,但是 LITE_RUNTIME 则仅仅打印字段值组成的字符串。
因此:可以在调试阶段使用 SPEED 模式,而上线以后提升性能使用 LITE_RUNTIME 模式优化。
最直观的区别是使用三种不同的 option 选项时,编译后产生的 .pb.h 中自定义的类所继承的 protobuf类不同:
//1. SPEED模式:(自定义的类继承自 Message 类)
// .proto 文件:
option optimize_for = SPEED;
// .pb.h 文件:
class Person : public ::PROTOBUF_NAMESPACE_ID::Message {};//2. CODE_SIZE模式:(自定义的类继承自 Message 类)
// .proto 文件:
option optimize_for = CODE_SIZE;
// .pb.h 文件:
class Person : public ::PROTOBUF_NAMESPACE_ID::Message {};//3. LITE_RUNTIME模式:(自定义的类继承自 MessageLite 类)
// .proto 文件:
option optimize_for = LITE_RUNTIME;
// .pb.h 文件:
class Person : public ::PROTOBUF_NAMESPACE_ID::MessageLite {};
参考:
1、https://zhuanlan.zhihu.com/p/594534435?utm_id=0
相关文章:
Ubuntu下使用protoBuf
一、protobuf简介: 1.1 protobuf的定义: protobuf是用来干嘛的? protobuf是一种用于 对结构数据进行序列化的工具,从而实现 数据存储和交换。 (主要用于网络通信中 收发两端进行消息交互。所谓的“结构数据”是指类…...
AT89S52单片机
目录 一.AT89S52单片机的硬件组成 1.CPU(微处理器) (1)运算器 (2)控制器 2.数据存储器 (RAM) (1)片内数据存储器 (2)片外数据存储器 3.程序存储器(Flash ROM) 4.定时器/计数器 5.中断系统 6.串行口 7.P0口、P1口、P2口和P3口 8.特殊功能寄存器 (SFR) 常用的特殊功…...
数字孪生智慧校园 Web 3D 可视化监测
当今,智慧校园发展阶段亟需推动信息可视化建设与发展,将大数据、云计算、可视化等高新技术相融合,为校园师生创造科学智能的学习环境,并实现教学资源最大化和信息服务智能化。帮助学校更好地应用校园可视化技术,提升校…...
Python Web框架的三强之争:Flask、Django和FastAPI
JetBrains 公布 2022 Python 开发者调查结果。 完整报告地址:https://lp.jetbrains.com/zh-cn/python-developers-survey-2022/ 这是由 Python 软件基金会 (PSF) 和 JetBrains 共同开展的第六次官方年度 Python 开发者调查,回复于 2022 年 10 月至 12 …...
本地缓存与分布式缓存
一、缓存的概念 在服务端编程当中,缓存主要是指将数据库的数据加载到内存中,之后对该数据的访问都在内存中完成,从而减少了对数据库的访问,解决了高并发场景中数据库容易成为性能瓶颈的问题;以及基于内存的访问速度高…...
LabVIEW如何获取波形图上游标所在位置的数值
LabVIEW如何获取波形图上游标所在位置的数值 获取游标所在位置数值的一种方法是利用波形图的游标列表属性。 在VI的程序框图中,右键单击波形图并选择创建引用 ,然后将创建的引用节点放在程序框图上。 在程序框图上放置一个属性节点,并将其…...
八股文面试day6
什么是代理?为什么要用动态代理? 代理模式大概意思是:为其他对象提供一个代理项或者是占位符,以控制对这个对象的访问 代理模式核心思想:创建一个代理对象,在客户端和目标对象之间的一个中介,…...
【Unity】EventSystem.current.IsPointerOverGameObject()对碰撞体起作用
本来我是用 EventSystem.current.IsPointerOverGameObject()来检测是否点击在UI上的,但是发现,他对我的碰撞体也是返回ture,研究半天。。。。找不出问题,然后发现我的相机上挂载了PhysicsRaycaster,去掉之后就好了,至于…...
形态学操作—闭运算
闭运算(Closing)是图像形态学中的一种操作,它结合了膨胀(Dilation)和腐蚀(Erosion)操作。闭运算的原理是先对图像执行腐蚀操作,然后再进行膨胀操作。这个过程能够消除图像中的小孔洞…...
HEVC-SCC rgb file input
关键字 csc allocateCSCBuffer()-> m_apcPicYuvCSC xCheckRDCostIntraCSC():更简单, enum ACTRDTestTypes { ACT_TWO_CLR 0, //two color space ACT_TRAN_CLR 1, //transformed color space ACT_ORG_CL…...
XG916Ⅱ轮式装载机后驱动桥设计机械设计CAD
wx供重浩:创享日记 对话框发送:装载机 获取完整论文报告工程源文件 本次设计内容为XG916Ⅱ装载机后驱动桥设计,大致上分为主传动的设计,差速器的设计,半轴的设计,最终传动的设计四大部分。其中主传动锥齿轮…...
pcr扩增原理中的变性 退火 延申扩增
一、PCR简介 聚合酶链式反应(PCR)是一种用于放大扩增特定的DNA片段的分子生物学技术,它可看作是生物体外的特殊DNA复制,PCR的最大特点是能将微量的DNA大幅增加。 二、PCR原理 1.背景 DNA的半保留复制是生物进化和传代的重要途…...
C语言——输入一个4位正整数,输出其逆数。
#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int i,j 0;int a1,a2,a3,a4;printf("输入一个4位正整数:\n");scanf("%d",&i);a1 i/1000; a2 i/100%10; a3 i/10%10; a4 i%10; printf("千位a1%d,百位a…...
jQuery_02 引入jQuery,初试牛刀
引入jquery文件 我们在官网上点击dowmload那个 会发现进入了一个网页,里面全部是代码,你可能还在想为什么下载不了,其实jquery不跟vue一样,整个jquery就是一个js文件而已,所以直接ctrla 全选 ctrlc复制 ,然…...
pandas获取年月第一天、最后一天,加一秒、加一天、午夜时间
Timestamp对象 # ts = pandas.Timestamp(year=2023, month=10, day=15, # hour=15, minute=5, second=50, tz="Asia/Shanghai") ts = pandas.Timestamp("2023-10-15 15:05:50", tz="Asia/Shanghai") # 2023-10-15 15:05…...
Unsupervised Condition GAN
Unsupervised Condition GAN主要有两种做法: Direct Transformation 直接输入domain X图片,经过Generator后生成对应的domain Y的图像。这种转化input和output不能够差太多。通常只能实现较小的转化,比如改变颜色等。 Projection to Commo…...
Crypto(11)HECTF-rsarsa(明文存在线性关系)
题目如下: from functools import reduce from Crypto.Util.number import * import random from secret import flag,hintdef generate_PQ(bits):x getPrime(bits) >> bits//2 << bits//2#右移bit//2位后左移bit//2位while True:p x random.getran…...
论文阅读 Forecasting at Scale (二)
最近在看时间序列的文章,回顾下经典 论文地址 项目地址 Forecasting at Scale 3.2、季节性 3.3、假日和活动事件3.4、模型拟合3.5、分析师参与的循环建模4、自动化预测评估4.1、使用基线预测4.2、建模预测准确性4.3、模拟历史预测4.4、识别大的预测误差 5、结论6、致…...
刷题感悟w
题目很长的一定要慢慢把题目的意思搞清楚 有重复操作不知道怎么办 可以用数组去标记 你好!在C中,replace 函数通常是用于替换容器(例如 std::vector 或 std::string)中的特定元素的函数。以下是 std::replace 函数的一般用法&…...
记一次linux操作系统实验
前言 最近完成了一个需要修改和编译linux内核源码的操作系统实验,个人感觉这个实验还是比较有意思的。这次实验总共耗时4天,从对linux实现零基础,通过查阅资料和不断尝试,直到完成实验目标,在这过程中确实也收获颇丰&…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
恶补电源:1.电桥
一、元器件的选择 搜索并选择电桥,再multisim中选择FWB,就有各种型号的电桥: 电桥是用来干嘛的呢? 它是一个由四个二极管搭成的“桥梁”形状的电路,用来把交流电(AC)变成直流电(DC)。…...
在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例
目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码:冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...
解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC…...
