【ProtoBuf】基础使用与编译

news2024/11/24 18:47:05

文章目录

  • ProtoBuf的使用
  • 基本使用
    • 指定proto3语法
    • package声明符
    • 定义消息(message)
    • 定义消息字段
    • 字段唯一编号
  • 编译
    • 序列化与反序列化
    • 序列化与反序列化使用

ProtoBuf的使用

在这里插入图片描述
流程如下:

  1. 编写 .proto文件,定义结构对象(message)及属性内容
  2. 使用 protoc 编译器编译 .proto文件,生成一系列接口代码,存放在新生成头文件和源文件中
  3. 依赖生成的接口,将编译生成的头文件包含进代码中,实现对 .proto文件中定义的字段进行设置和获取,和对 message 对象进行序列化和反序列化

基本使用

通过实现一个简单的通讯录项目作例子

文件规范:创建 .proto文件时,文件命名应该使用全小写字母命名,多个字母之间使用_连接,如lower_snake_case.proto

添加注释:.proto文件添加注释,可以使用///*...*/

指定proto3语法

Protocol Buffer语言版本3,简称 proto3。proto3简化了 Protocol Buffer语言,既易于使用,又可以子啊更广泛的编程语言中使用。允许使用 C++,Java,Python等多种语言生成protocol buffer代码
在 .proto文件中,要使用syntax="proto3";来指定文件语法为proto3,并且必须写在除去注释内容的第一行。如果没有指定,编译器会使用proto2语法

//注释1
syntax = "proto3";//除去注释的第一行

package声明符

package 是一个可选的声明符,能表示 .proto文件的命名空间,经protoc编译器会生成为namespace,在项目中要有唯一性。作用是避免定义的消息出现冲突

syntax = "proto3";//语法规则
package contacts;//命名空间

定义消息(message)

消息(message):要定义的结构化对象,经由 protoc编译器生成为class

//.proto文件中定义一个消息类型的格式为:
message 消息类型名{
}
//消息类型命名规范:使用驼峰命名法,首字母大写 

示例:

syntax = "proto3";
package contacts;
//定义联系人信息
message PeopleInfo{

}

定义消息字段

在message中我们可以定义其属性字段,字段定义格式为:字段类型 字段名 = 字段唯一编号;

  • 字段名称命名规范:全小写字母,多个字母之间使用_连接
  • 字段类型分为:标量数据类型特殊类型(包括枚举、其他消息类型等)
  • 字段唯一编号:用来识别字段,一旦开始使用就不能再改变

下表展示标量数据类型,及经编译后自动生成的类中与之对应的类型

.proto 类型说明C++ 类型
doubledouble
floatfloat
int32使用变长编码[1]。负数的编码效率较低——若字段可能为负值,应使用sint32代替int32
int64使用变长编码[1]。负数的编码效率较低——若字段可能为负值,应使用sint64代替int64
uint32使用变长编码[1]uint32
uint64使用变长编码[1]uint64
sint32使用变长编码[1]。符号整型,负值的编码效率高于常规的int32类型int32
sint64使用变长编码[1]。符号整型,负值的编码效率高于常规的int64类型int64
fixed32定长4字节,若值常大于2 ^ 28则会比uint32更高效uint32
fixed64定长8字节,若值常大于2 ^ 56则会比uint64更高效uint64
sfixed32定长4字节int32
sfixed64定长8字节int64
boolbool
string包含UTF-8和ASCII编码的字符串,长度不能超过2^32string
bytes可包含任意的字节序列但长度不能超过2^32string

变长编码[1]:经过protobuf编码后,原本4字节或8字节的数可能会被变为其他字节数

PeopleInfo添加字段

syntax = "proto3";
package contacts;

message PeopleInfo{
	string name = 1;
	int32 age = 2;
}

字段唯一编号

字段唯一编号的范围:

1 ~ 2^29 - 1(536870911),其中19000 ~ 19999不可用
不可用的部分是Protobuf协议对这些数进行了预留,如果使用了这些编号,在编译时会报警

//例将name字段编号定位19000
string name = 19000
Field numbers 19000 through 19999 are reserved for protobuf implementation

PS:范围1 ~ 15的字段编号只需要一个字节进行编码,16 ~ 2047 内的数字需要两个字节编码。编码后的字节不仅包含了编号,还有字段类型。所以可以使用1 ~ 15用来标记出现非常频繁的字段

编译

编译命令格式如下:

protoc [--proto_path=import_path] -cpp_out=dst_dir path/file.proto

protoc:是Protocol Buffer 提供的命令行编译工具
proto_path:指定 被编译的.proto文件所在目录,可多次指定。可简写为 -I
import_path:如果不指定,则默认在当前目录搜索
--cpp_out=:指示编译后的文件为C++文件
out_dir:编译后生成文件的目标路径
path/file.proto:要编译的.proto文件

示例:如果.proto文件在当前目录下,编译后的文件也直接生成在当前目录

protoc --cpp_out=. ./contacts.proto

1. 因为编译文件在当前目录,可以不指明搜索路径,省略 -I
2. --cpp_out=.  生成C++文件,且生成在当前目录
3. ./contacts.proto   指明编译的.proto文件

示例:如果.proto文件在上级目录,将编译后的文件生成在当前目录的dir子文件夹中

protoc -I ../ --cpp_out=./dir ../contacts.proto

1. -I ../   		  指明搜索路径是上级目录
2.  --cpp_out=./dir   指明输出C++文件到dir文件夹中
3. ../contacts.proto  指明要编译的.proto文件 

对于编译后生成的contacts.pb.hcontacts.pb.cc包含以下内容

  • 对于每个message,都会生成一个对应的消息类
  • 在消息类中,编译器为每个字段提供了获取和设置方法,以及一些能够操作字段的方法
  • .h文件为声明,.cc文件为实现
  • 字段的获取方法,名称同小写字段名相同,如字段名为name,就通过name()获取;设置方法名称以 set_开头,如set_name()
  • 每个字段都有一个 clear_(),可以将字段重新设置为 empty状态

序列化与反序列化

.proto文件编译生成的类都继承自MessageLite,序列化方法和反序列化方法也是从中继承

class MessageList
{
public:
	//序列化:
	bool SerializeToOstream(string* output) const;
	bool SerializeToArray(string* output) const;
	bool SerializeToString(string* output) const;
 
 //反序列化:
 bool ParseFromIstream(istream* input); // 从流中读取数据,再进⾏反序列化动作
 bool ParseFromArray(const void* data, int size);
 bool ParseFromString(const string& data);
};
  • 序列化的结果为二进制字节序列,而非文本格式
  • 以上三种序列化方法没有本质区别,只是序列化后的输出格式不同,可以供不同应用场景使用
  • 序列化的API函数均为const成员函数,因为序列化不会改变类对象的内容,而是将序列化的结果保存到函数入参指定的地址中
  • 详细message API 可以参见 完整列表

序列化与反序列化使用

创建⼀个测试文件main.cc,实现:

  • 对⼀个联系⼈的信息进行序列化,并将结果打印出来
  • 对序列化后的内容反序列,解析出联系⼈信息并打印出来

main.cc

#include<iostream>
#include"contacts.pb.h"//引⼊编译⽣成的头⽂件
usingnamespacestd;
int main() 
{
	string people_str;
	{
		// .proto⽂件声明的package,通过protoc编译后,会为编译⽣成的C++代码声明同名的命名空间
		//其范围是在.proto⽂件中定义的内容
		contacts::PeopleInfo people;
		people.set_age(20);
		people.set_name("张珊");
		//调⽤序列化⽅法,将序列化后的⼆进制序列存⼊string中
		if(!people.SerializeToString(&people_str))
			cout <<"序列化联系⼈失败."<< endl;
		//打印序列化结果
		cout <<"序列化后的people_str: "<< people_str << endl;
	}
	{
		contacts::PeopleInfo people;
		//调⽤反序列化⽅法,读取string中存放的⼆进制序列,并反序列化出对象
		if(!people.ParseFromString(people_str)) {cout <<"反序列化出联系⼈失败."<< endl;
		}
		//打印结果
		cout <<"Parse age: "<< people.age() << endl;
		cout <<"Parse name: "<< people.name() << endl;
	}
}

用如下命令编译main.cc,生成可执行程序:

g++ main.cc contacts.pb.cc -o test -std=c++11 -lprotobuf

需要链接protobuf动态库

相对于xml和JSON,因为protobuf是将字段编码为二进制,破解成本增大,所以相对安全


以上就是本篇博客的所有内容,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2209007.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

常用类(二)--String类的简单总结

文章目录 1.基本介绍1.1创建对象1.2找到对应下标的字符1.3找到对应字符的下标1.4指定位置开始遍历1.5反向进行遍历1.6大小写之间的转换1.7字符串转换为数组1.8元素的替换1.9字符串的分割1.10字符串的截取 2.StringBuilder和StringBuffer2.1 StringBuilder的引入2.2面试题目 1.基…

拆解学习【无线充,EMMC,锂电池电量计,OTA】(二)

主要学习到了&#xff1a;无线充&#xff0c;EMMC&#xff0c;手表CPU方案&#xff0c;锂电池电量计&#xff0c;OTA。 无线充电功能是产品的核心卖点之一&#xff0c;充电头网通过拆解发现&#xff0c;手表内部使用恒玄BES2500BP智能手表单芯片解决方案&#xff0c;内置四核C…

BetterZip怎么导入文件进行压缩?苹果解压软件怎么用?

BetterZip作为苹果系统常用的压缩文件软件之一&#xff0c;具有使用方便、压缩导出格式多、兼容性强等特点。我们要使用BetterZip进行文件压缩时&#xff0c;首先需要将文件导入到BetterZip才可以。 关于BetterZip的文件导入方式&#xff0c;主要有几种&#xff0c;今天我来给…

垂直AI大模型行业全景分析及发展趋势研究报告

2024-10-12调研咨询机构环洋市场咨询出版的【全球垂直AI大模型行业总体规模、主要厂商及IPO上市调研报告&#xff0c;2024-2030】只要调研全球垂直AI大模型总体规模&#xff0c;主要地区规模&#xff0c;主要企业规模和份额&#xff0c;主要产品分类规模&#xff0c;下游主要应…

每日一题|3158. 求出出现两次数字的 XOR 值|哈希

题目给的范围很小&#xff0c;50以内&#xff0c;所以什么数据结构都可以。 这里采用set来维护访问过的数字&#xff0c;利用哈希来提升时间效率。 class Solution:def duplicateNumbersXOR(self, nums: List[int]) -> int:visited set()l []res 0for i in nums:if i i…

游戏如何应对薅羊毛问题

在大众眼里&#xff0c;“薅羊毛”是指在电商领域&#xff0c;“羊毛党”利用平台、商家的促销规则&#xff0c;低价获取商品和服务的行为。如前不久“小天鹅被一夜薅走7000万”的案例震惊全网。 然而实际上&#xff0c;“薅羊毛”现象不仅存在于电商场景&#xff0c;在游戏中…

【Unity】TextMeshPro 3.0.9无法显示emoji表情问题

需要下载TextMeshPro 3.2.x-pre.xxx版本&#xff0c;重新生成Sprite Asset文件解决 注意&#xff1a;若Package Manager没有搜到pre版本&#xff0c;那么可以去github下载到本地&#xff0c;再解压后&#xff0c;将文件夹移动到工程Packages文件夹下&#xff0c;然后打开Packa…

基于SpringBoot的体育商城购物系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

React复习

文章目录 常用的HooksuseStateuseReduceruseRefuseContextuseMemouseCallbackuseEffect 组件通信Props&#xff08;属性&#xff09;Ref&#xff08;引用&#xff09;Context&#xff08;上下文&#xff09;State&#xff08;状态&#xff09;回调函数Event Bus&#xff08;事件…

Python WebSocket 的原理及其应用

Python WebSocket 的原理及其应用 在现代 Web 开发中&#xff0c;实时通信成为了越来越多应用的重要组成部分。尤其是像聊天应用、实时数据更新、在线游戏等场景&#xff0c;服务器与客户端之间的即时数据传输需求非常迫切。在传统的 HTTP 协议中&#xff0c;通信往往是基于请…

在docker的容器内如何查看Ubuntu系统版本

文章目录 写在前面一、问题描述二、解决方法参考链接 写在前面 自己的测试环境&#xff1a; docker 一、问题描述 由于 lsb_release -a 只能查看自己电脑&#xff08;宿主机&#xff09;的系统版本&#xff0c;如果在docker的容器内又应该如何查看Ubuntu系统版本呢&#xff…

GoPro 解决方案:恢复 GoPro 数据、GoPro 重置为出厂设置

在本文中&#xff0c;我们将向您展示如何轻松将 GoPro 相机重置为出厂设置以及如何从已重置为出厂设置的 GoPro 中恢复丢失的数据。 第 1 部分&#xff1a;将 GoPro 重置为出厂设置后恢复丢失的数据。 ​在将 GoPro 重置为出厂设置之前&#xff0c;最好对视频进行完整备份。但…

URDF统一机器人建模语言

统一机器人建模语言 URDF&#xff08;Unified Robot Description Format&#xff09;统一机器人描述格式&#xff0c;URDF使用XML格式描述机器人文件。 我们从下面四个方面介绍URDF&#xff1a; URDF的组成介绍 URDF-Link介绍 URDF-Joint介绍 创建一个简单的URDF…

大数据新视界 --大数据大厂之差分隐私技术在大数据隐私保护中的实践

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

ribbon和nginx负载均衡图解

通俗来说 nginx&#xff1a; 规定一个地址v&#xff08;比如v代理了地址a,b,c,d且他们都实现了同一个服务e&#xff09;&#xff0c;然后当我们的请求想要实现e服务而去请求v的时候&#xff0c;v实际上就会从a,b,c,d中选一个来让他们给请求者提供服务。 ribbon&#xff1a; …

[Halcon矩阵] 通过手眼标定矩阵计算相机旋转角度

&#x1f4e2;博客主页&#xff1a;https://loewen.blog.csdn.net&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由 丶布布原创&#xff0c;首发于 CSDN&#xff0c;转载注明出处&#x1f649;&#x1f4e2;现…

idear2024-Springcloud项目一个服务创建多个实例/端口

国庆重装系统&#xff0c;安装了最新版的idear,结果带来一堆bug。 解决办法&#xff1a; 初始配置&#xff1a; 初始状态&#xff1a; 1.点击右上角3个点&#xff0c;再点击编辑 2.点击修改选项 3.点击允许多个实例 可以发现下面多了个选项 点击&#xff1a;应用-》确定 4.修…

windows自动化(一)---windows关闭熄屏和屏保

电脑设置关闭屏幕和休眠时间不起作用解决方案 一共三个方面注意&#xff1a; 一、关闭屏保设置&#xff1a; 二、电源管理设置 三、关闭盖子不做操作&#xff1a; 第一点很重要&#xff0c;就算二三都做了&#xff0c;一没做&#xff0c;照样不行。

win软件 超强的本地视频 图片去水印 动态水印!

AI视频图片去水印 HitPaw Watermark Remover 电脑软件&#xff0c;内涵安装教程&#xff0c;以后看到有水印的视频不怕啦&#xff0c;用这个就行了&#xff0c;可以去除动态水印&#xff01; 【下载】 https://pan.quark.cn/s/1ba6f088f0b2 【应用名称】:HitPaw Watermark R…

[Linux] Linux 进程程序替换

标题&#xff1a;[Linux] Linux 进程程序替换 个人主页水墨不写bug &#xff08;图片来源于网络&#xff09; 目录 O、前言 一、进程程序替换的直观现象&#xff08;什么是进程程序替换&#xff1f;&#xff09; 二、进程程序替换的原理 三、进程程序替换的函数&#xff08…