【ProtoBuf】基础使用与编译

文章目录

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

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

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

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

protoc -I ../ --cpp_out=./dir ../contacts.proto1. -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.rhkb.cn/news/445509.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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

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

GS-SLAM论文阅读笔记-MGSO

前言 MGSO首字母缩略词是直接稀疏里程计(DSO)&#xff0c;我们建立的光度SLAM系统和高斯飞溅(GS)的混合。这应该是第一个前端用DSO的高斯SLAM&#xff0c;不知道这个系统的组合能不能打得过ORB-SLAM3&#xff0c;以及对DSO会做出怎么样的改进以适应高斯地图&#xff0c;接下来…

一次性语音芯片:重塑语音识别技术,引领智能化生活新时代

随着一次性语音芯片的突破性进展&#xff0c;语音识别技术正融入我们生活的方方面面&#xff0c;引领着智能化生活迈向一个全新的时代。这些芯片不仅体积小巧、成本低廉&#xff0c;更在性能上实现了质的飞跃&#xff0c;能够更精确地捕捉并理解人类语音。本文将解读关于一次性…

Crypto虐狗记---”你“和小鱼(五)

前言&#xff1a;剧情五 提示&#xff1a; 一种食物&#xff1f; 一种食物——培根&#xff1a;&#xff08;A B 也暗示是培根加密&#xff09; cyberpeace{attackanddefenceworldisinteresting} 密码学笔记——培根密码 - ILK - 博客园 (cnblogs.com)

Appium Device Farm安装教程

环境要求&#xff1a;Appium version ≥ 2.4.X 安装appium npm install -g appium2.11.3 如果安装提示如下问题 npm error code EEXIST npm error syscall rename npm error path /Users/wan/.npm/_cacache/tmp/d5787519 npm error dest /Users/wan/.npm/_cacache/content-…

Android一个APP里面最少有几个线程

Android一个APP里面最少有几个线程 参考 https://www.jianshu.com/p/92bff8d6282f https://www.jianshu.com/p/8a820d93c6aa 线程查看 Android一个进程里面最少包含5个线程&#xff0c;分别为&#xff1a; main线程(主线程&#xff09;FinalizerDaemon线程 终结者守护线程…

cnn突破七(四层bpnet网络公式与卷积核bpnet公式相关)

我们要有一个概念&#xff0c;就是卷积核就是我们的w1&#xff0c;w12&#xff0c;w2 那么我们的5*5卷积核怎么表达&#xff0c;当他在14*14的图像中流动时&#xff0c;对应的像素也在变化 这个和我们的上面w1&#xff0c;w12&#xff0c;w2不同&#xff0c;因为这几个都是全…

7. 整数反转【数学】

文章目录 7. 整数反转解题思路Go代码 7. 整数反转 7. 整数反转 给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。 如果反转后整数超过 32 位的有符号整数的范围 [ − 2 31 , 2 31 − 1 ] [−2^{31}, 2^{31} − 1] [−231,231−1] &#xff0…

数学建模算法与应用 第12章 现代优化算法

目录 12.1 粒子群优化算法 Matlab代码示例&#xff1a;粒子群优化算法求解函数最小值 12.2 遗传算法 Matlab代码示例&#xff1a;遗传算法求解函数最小值 12.3 蚁群算法 Matlab代码示例&#xff1a;蚁群算法求解旅行商问题 12.4 Matlab 遗传算法工具 使用遗传算法工具箱…

U盘误删文件?一招教你轻松找回!

大家好&#xff01;今天咱们来聊聊一个让人头疼却又常见的问题——U盘数据丢失。是不是有时候不小心删了个文件&#xff0c;或者格式化了U盘&#xff0c;结果发现重要资料不见了&#xff0c;心里那个急啊&#xff01;别急&#xff0c;别急&#xff0c;今天我就给大家推荐几款免…

Scalable TCP 如何优化长肥管道

来看一个极简的拥塞控制实现 net/ipv4/tcp_scalable.c&#xff0c;去掉注释不到 50 行代码。它的介绍在 Scalable TCP-improving performance in highspeed networks。由于太简单&#xff0c;估计没什么人会在意。 本文说一下它背后的道理。 无论 bic/cubic&#xff0c;westw…

leetcode:反转字符串II

题目链接 string reverse(string s1) {string s2;string::reverse_iterator rit s1.rbegin();while (rit ! s1.rend()){s2 *rit;rit;}return s2; } class Solution { public:string reverseStr(string s, int k) {string s1;int i 0;//标记字符串下标int j 0;int length …

react+ts+vite 别名一直爆红问题

已经配置如下代码安装了types/node import path from "path"; // https://vitejs.dev/config/ export default defineConfig({plugins: [react()],server: {proxy: {"/api": {target: "http://localhost:3000",changeOrigin: true,rewrite: (pa…

数字电路尚硅谷学习笔记

学习视频&#xff1a;01_数字电路_从零搭建计算机引导_哔哩哔哩_bilibili 第1章数字电路基础 1.引言 数字电路是现代科技和工程领域中不可或缺的基础。从计算机系统到通信设备&#xff0c;从家庭电子产品到工业自动化&#xff0c;数字电路无处不在&#xff0c;影响着我们的生…

手写mybatis之解析和使用ResultMap映射参数配置

前言 学习源码是在学习什么呢&#xff1f; 就是为了通过这些源码级复杂模型中&#xff0c;学习系统框架的架构思维、设计原则和设计模式。在这些源码学习手写的过程中&#xff0c;感受、吸收并也是锻炼一种思维习惯&#xff0c;并尝试把这些思路技术迁移到平常的复杂业务设计开…

1.MySQL存储过程基础(1/10)

引言 数据库管理系统&#xff08;Database Management System, DBMS&#xff09;是现代信息技术中不可或缺的一部分。它提供了一种系统化的方法来创建、检索、更新和管理数据。DBMS的重要性体现在以下几个方面&#xff1a; 数据组织&#xff1a;DBMS 允许数据以结构化的方式存…

“云计算+高职”:VR虚拟仿真实训室的发展前景

随着科技的飞速进步&#xff0c;云计算与虚拟现实&#xff08;VR&#xff09;技术的结合正在深刻改变着教育领域&#xff0c;尤其是在高等职业教育中&#xff0c;这一融合为实训教学带来了革命性的变革。VR虚拟仿真实训室作为这一变革的前沿阵地&#xff0c;正展现出广阔的发展…

Chromium 如何查找V8 引擎中JavaScript 标准内置对象

JavaScript 标准内置对象 - JavaScript | MDN (mozilla.org) 一、JavaScript 标准内置对象 本章介绍和说明了 JavaScript 中所有的标准内置对象、以及它们的方法和属性。 这里的术语“全局对象”&#xff08;或标准内置对象&#xff09;不应与 global 对象混淆。这里的“全局…

出海快报 | “三消+短剧”手游横空出世,黄油相机“出圈”日本市场,从Q1看日本手游市场趋势和机会

编者按&#xff1a;TopOn出海快报栏目为互联网出海从业者梳理出海热点&#xff0c;供大家了解行业最新发展态势。 1.“三消短剧”横空出世&#xff0c;融合创新手游表现亮眼 随着竞争的加剧&#xff0c;新产品想要突出重围&#xff0c;只能在游戏中加入额外的元素。第一次打开…

Spring Boot项目的创建与使用

1.SpringBoot初识 SpringBoot是什么 介绍 ​ 为了简化 Spring 应用的搭建和开发过程&#xff0c;Pivotal 团队在 Spring 基础上提供了一套全新的开源的框架&#xff0c;它就是 Spring Boot。 Spring Boot是由Pivotal团队提供的全新&#xff0c;其设计目的是用来新应用的初始…