当前位置: 首页 > news >正文

【ProtoBuf】使用指南

一.什么是ProtoBuf

特点:ProtoBuf是用于序列化和反序列化的一种方法,类似xml和json,但是效率更高,体积更小。ProtoBuf具有语⾔⽆关、平台⽆关,扩展性、兼容性好等特点。

ProtoBuf是需要依赖通过编译生成的头文件和源文件来使用的。也就是说他需要参与到编译链接的过程中。

使用方法简单来说,我们之需要写一个包含待处理数据的message,就可以通过protoc编译器编译.proto文件自动生成接口,在后续业务逻辑中我们直接使用这些接口即可。

二.形成proto文件

在protobuf里面定义的结构化对象叫message,在这个结构化对象中定义其对应的属性内容。在这里我们使用proto3语法,需要手动指定。同时指定包(类比命名空间)。

定义消息字段:字段类型+字段名=字段唯⼀编号。

这里的字段类型和c++一致(在类型后面带上位数)。字段唯⼀编号是⽤来标识字段,⼀旦开始使⽤就不能够再改变。但注意,这里有可能存在变长编码,变⻓编码是指:经过protobuf编码后,原本4字节或8字节的数可能会被变为其他字节数。

通过以上知识就能得到如下用例。

syntax = "proto3";  //指定语法
package contacts;   //命名空间message StudentInfo
{string name = 1;  // 姓名int age = 2;    // 年龄  
}

字段唯⼀编号的范围:1~536,870,911(2^29-1),其中19000~19999不可⽤。范围为1~15的字段编号需要⼀个字节进⾏编码,16~2047内的数字需要两个字节进⾏编码。编码后的字节不仅只包含了编号,还包含了字段类型。1~15要⽤来标记出现⾮常频繁的字段。

接下来编译生成C++文件
编译命令格式:protoc [--proto_path=IMPORT_PATH] --cpp_out=DST_DIR path/to/file.proto

【】内可以省略

在这里就可以是protoc --cpp_out=. contacts.proto 

编译后⽣成了两个⽂件: contacts.pb.h  contacts.pb.cc,

对于编译⽣成的C++代码,包含了以下内容:

  • 对于每个message,都会⽣成⼀个对应的消息类。
  • 在消息类中,编译器为每个字段提供了获取和设置⽅法
  • 编辑器会针对于每个.proto ⽂件⽣成 .h 和 .cc ⽂件,分别⽤来存放类的声明与类的实现
     

这样就能得到基本的操作接口,类似这种 

接下来就可以使用序列化和反序列化了在消息类的⽗类中能找到MessageLite,这里提供了序列化反序列化的接口。

//序列化:
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);

这样就能把数据结构转换为二进制结构。详情可参考protobuf官网。这样就能实现从序列化到反序列的整体逻辑,注意在编译的时候要告知编译器所使用的库名称。

三.详细语法
 

一.字段规则

  • singular:消息中可以包含该字段零次或⼀次(不超过⼀次)。proto3语法中,字段默认使⽤该规则
  • repeated:消息中可以包含该字段任意多次(包括零次),其中重复值的顺序会被保留。可以理解为定义了⼀个数组
    syntax = "proto3";
    package contacts;message StudentInfo 
    {
    string name = 1;
    int32 age = 2;
    repeated string phone_numbers = 3;    //能有多个电话
    }
    
     

二.使用消息字段

proto里的消息体是可以重复嵌套的。

同时消息类型是可以充当字段来使用的。

syntax = "proto3";
package contacts;message StudentInfo 
{string name = 1;int32 age = 2;message Phone{string number = 1;}repeated Phone phone = 3;}

我们也可以在一个proto内部导入其他proto的消息类型

//使用 import 导入其他类型的proto文件
import "phone.proto"; // 引⼊的⽂件声明了package,使⽤消息时,需要⽤ ‘命名空间.消息类型’ 格式message test
{phone.Phone phone = 1;
}

注意在使用api对消息类型进行赋值的时候有两个接口,mutable_⽅法,返回值为消息类型的指针,这类方法会为我们开辟好空间,可以直接对这块空间的内容进⾏修改。或用 set_allocated_这个函数需要手动传入一个你自己开辟好的空间。

三.enum 类型

要注意枚举类型的定义有以下几种规则:
1. 0值常量必须存在,且要作为第⼀个元素。这是为了与proto2的语义兼容:第⼀个元素作为默认
值,且值为0。
2. 枚举类型可以在消息外定义,也可以在消息体内定义(嵌套)。
3. 枚举的常量值在32位整数的范围内。但因负值⽆效因⽽不建议使⽤(与编码规则有关)

同时具有相同枚举值名称不能出现在同一级别下。同级(同层)的枚举类型,各个枚举类型中的常量不能重名。
• 单个.proto⽂件下,最外层枚举类型和嵌套枚举类型,不算同级。
• 多个.proto⽂件下,若⼀个⽂件引⼊了其他⽂件,且每个⽂件都未声明package,每个proto⽂
件中的枚举类型都在最外层,算同级。
• 多个.proto⽂件下,若⼀个⽂件引⼊了其他⽂件,且每个⽂件都声明了package,不算同级。
 

在使用枚举类型的时候使用诸如set_,或者type,用来设置和获取枚举类型

四.Any类型

Any类型可以看成c++的auto泛型类型,使⽤时可以在Any中存储任意消息类型,Any类
型的字段也⽤repeated来修饰。注意在使用的时候引入any.proto

import "google/protobuf/any.proto";message test
{google.protobuf.Any data = 1;
}

对于any类型来说,设置方法可以用mutable方法修改。

any类型可以和普通类型之间可以互相转换,使用PackFrom() 方法可以将任意消息类型转为 Any 类型。使⽤ UnpackTo() ⽅法可以将 Any 类型转回之前设置的任意消息类型。使用 Is() 方法可以⽤来判断存放的消息类型是否为 typename T。

五.oneof类型

表示这其中的字段同时只有一个字段会被设置。同时oneof里不能设置repeated,若是在oneof里多次设置,则会保留最后一次设置字段属性,可以用诸如_case方法获取设置了哪一个字段

六.map类型

可以类比c++中的map类型

map<key_type, value_type> map_field = N;

注意key值不能是float或者double.使用map方法也用mutable方法进行设置

四.语法的细节处理

  •  对于字符串,默认值为空字符串。
  •  对于字节,默认值为空字节。
  •  对于布尔值,默认值为false。
  •  对于数值类型,默认值为0。、
  • 对于枚举,默认值是第⼀个定义的枚举值,必须为0。
  • 于设置了repeated的字段的默认值是空的(通常是相应语⾔的⼀个空列表)
  • 对于 消息字段 、 oneof字段 和 any字段 ,C++和Java语⾔中都有has_⽅法来检测当前字段
    是否被设置
     

更新消息字段:

  • 禁⽌修改任何已有字段的字段编号。
  • 若是移除⽼字段,要保证不再使⽤移除字段的字段编号。正确的做法是保留字段编号(reserved),以确保该编号将不能被重复使⽤。不建议直接删除或注释掉字段。
  • int32,uint32,int64,uint64和bool是完全兼容的。可以从这些类型中的⼀个改为另⼀个,⽽不破坏前后兼容性。若解析出来的数值与相应的类型不匹配,会采⽤与C++⼀致的处理⽅案(例如,若将64位整数当做32位进⾏读取,它将被截断为32位)。
  • sint32和sint64相互兼容但不与其他的整型兼容。
  •  string和bytes在合法UTF-8字节前提下也是兼容的。
  •  fixed32与sfixed32兼容,fixed64与sfixed64兼容。
  • oneof:
    ◦ 将⼀个单独的值更改为新oneof类型成员之⼀是安全和⼆进制兼容的。
    ◦ 若确定没有代码⼀次性设置多个值那么将多个字段移⼊⼀个新oneof类型也是可⾏的。
    ◦ 将任何字段移⼊已存在的oneof类型是不安全的。

 如果删除一个字段后用新的字段占据了这个编号,在反序列化的时候就会解析出错误的信息。

若是新设置了字段,但却仍然使用就的方法序列化的话,新增的字段在旧程序中其实并没有丢失,⽽是会作为旧程序的未知字段。

未知字段:

在了解未知字段之前先需要知道一下protobuf之间不同类的关系。

MessageLite仅仅提供序列化、反序列化功能,跟message属于同一个层级,是message类的拓展。

Descriptor类是描述和管理message属性的类,是message类的下层。

Reflection主要提供了动态读写消息字段的接⼝,对消息对象的⾃动读写主要通过该类完成。提供⽅法来动态访问/修改message中的字段,对每种类型,Reflection都提供了⼀个单独的接⼝⽤于读写字段对应的值。类中还包含了访问/修改未知字段的⽅法。是message类的下层

UnknownFieldSet类
包含在分析消息时遇到但未由其类型定义的所有字段。是Reflection类的下层

UnknownField类

表⽰未知字段集中的⼀个字段,是UnknownFieldSet的下层。这里是未知字段的类型

enum Type {
TYPE_VARINT,
TYPE_FIXED32,
TYPE_FIXED64,
TYPE_LENGTH_DELIMITED,
TYPE_GROUP
};

当我们想拿到未知字段需要一层一层获取它的上层对象

//这里以people的字段为例
const Reflection* reflection = PeopleInfo::GetReflection();
const UnknownFieldSet& unknowSet = reflection->GetUnknownFields(people);for (int j = 0; j < unknowSet.field_count(); j++)
{const UnknownField& unknow_field = unknowSet.field(j);
}

五.选项option

.proto⽂件中可以声明许多选项,使⽤option 标注。选项能影响proto编译器的某些处理⽅式。


常用选项列举
 

 optimize_for:

该选项为文件选项,可以设置protoc编译器的优化级别,分别为SPEED 、
CODE_SIZE 、 LITE_RUNTIME 。受该选项影响,设置不同的优化级别,编译.proto⽂件后⽣
成的代码内容不同

SPEED :protoc编译器将⽣成的代码是⾼度优化的,代码运⾏效率⾼,但是由此⽣成的代码编译后会占⽤更多的空间。 SPEED 是默认选项
CODE_SIZE :proto编译器将⽣成最少的类,会占⽤更少的空间,是依赖基于反射的代码来
实现序列化、反序列化和各种其他操作。但和 SPEED 恰恰相反,它的代码运⾏效率较低。这
种⽅式适合⽤在包含⼤量的.proto⽂件,但并不盲⽬追求速度的应⽤中。

LITE_RUNTIME :⽣成的代码执⾏效率⾼,同时⽣成代码编译后的所占⽤的空间也是⾮常
少。这是以牺牲ProtocolBuffer提供的反射功能为代价的,仅仅提供encoding+序列化功能,
所以我们在链接库时仅需链接libprotobuf-lite,⽽⾮libprotobuf。这种模式通常⽤于资源
有限的平台,例如移动⼿机平台中
 

 option optimize_for = SPEED;

allow_alias:

 允许将相同的常量值分配给不同的枚举常量,⽤来定义别名。该选项为枚举选项。

 enum TestType

{
        option allow_alias = true;
        test1 = 0;
        test2= 1;
        test3 = 1; // 若不加 option allow_alias = true; 这⼀⾏会编译报错
}

相关文章:

【ProtoBuf】使用指南

一.什么是ProtoBuf 特点&#xff1a;ProtoBuf是用于序列化和反序列化的一种方法&#xff0c;类似xml和json&#xff0c;但是效率更高&#xff0c;体积更小。ProtoBuf具有语⾔⽆关、平台⽆关&#xff0c;扩展性、兼容性好等特点。 ProtoBuf是需要依赖通过编译生成的头文件和源…...

Buffer Pool

Buffer Pool 概念free链表flush链表LRU链表chunk 概念 MySQL在启动时向操作系统申请的一片连续的内存&#xff0c;默认128M。然后将这块内存分为一个一个缓冲页(16KB&#xff0c;因为页就是16KB的)。再为每个缓冲页创建对应的控制块用于管理。比如第一次查询数据之后&#xff…...

jetson-inference----docker内运行分类任务

系列文章目录 jetson-inference入门 jetson-inference----docker内运行分类任务 文章目录 系列文章目录前言一、进入jetson-inference的docker二、分类任务总结 前言 继jetson-inference入门 一、进入jetson-inference的docker 官方运行命令 进入jetson-inference的docker d…...

Python脚本之操作Redis Cluster【二】

本文为博主原创&#xff0c;未经授权&#xff0c;严禁转载及使用。 本文链接&#xff1a;https://blog.csdn.net/zyooooxie/article/details/112484045 之前写过一篇 使用redis-py来操作redis集群&#xff0c; https://blog.csdn.net/zyooooxie/article/details/123760358 &am…...

认识数学建模

文章目录 1 什么是数学建模2 数学建模的比赛形式3 参加数学建模的好处4 数学建模的流程5 数学建模成员分工6 数学建模常用软件7 数学建模竞赛7.1 美国大学生数学建模竞赛7.2 MathorCup高校数学建模挑战赛7.3 华中杯大学生数学建模挑战赛7.4 认证杯数学建模网络挑战赛7.5 华东杯…...

计算机工作原理解析和解剖(基础版)

我们会从软件⼯程师的⻆度解释计算机是如何⼯作的&#xff0c;我们的主要⽬标既不是期待 ⼤家可以造出⾃⼰的计算机&#xff0c;也不是介绍如何编程&#xff0c;⽽是希望让⼤家了解计算机的核⼼⼯作机制后&#xff0c;打破计算机的神秘感&#xff0c;并且有利于理解我们平时编程…...

外网ssh远程连接服务器

文章目录 外网ssh远程连接服务器一、前言二、配置流程1. 在服务器上安装[cpolar](https://www.cpolar.com/)客户端2. 查看版本号&#xff0c;有正常显示版本号即为安装成功3. token认证4. 简单穿透测试5. 向系统添加服务6. 启动cpolar服务7. 查看服务状态8. 登录后台&#xff0…...

滴滴基于 Ray 的 XGBoost 大规模分布式训练实践

背景介绍 作为机器学习模型的核心代表&#xff0c;XGBoost 在滴滴众多策略算法业务场景中发挥着至关重要的作用。因此&#xff0c;保障并持续提升 XGBoost 模型的离线训练及在线推理稳定性一直是机器学习平台的重点工作。同时&#xff0c;面对多样化的业务场景定制需求和数据规…...

k8s从入门到实践

k8s从入门到实践 介绍 Kubernetes&#xff08;简称k8s&#xff09;和Docker Swarm是两个流行的容器编排工具&#xff0c;它们都可以帮助用户管理和部署分布式应用&#xff0c;尤其是基于容器的应用。以下是两者的主要特点和对比&#xff1a; Kubernetes (k8s)&#xff1a; 开…...

Qt5.12.0 与 VS2017 在 .pro文件转.vcxproj文件

一、参考资料 stackoverflow qt - How to generate .sln/.vcproj using qmake - Stack Overflowhttps://stackoverflow.com/questions/2339832/how-to-generate-sln-vcproj-using-qmake?answertabtrending#tab-topqt - 如何使用 qmake 生成 .sln/.vcproj - IT工具网 (coder.wo…...

金蝶云星空 ServiceGateway RCE漏洞复现

0x01 产品简介 金蝶云星空是一款云端企业资源管理(ERP)软件,为企业提供财务管理、供应链管理以及业务流程管理等一体化解决方案。金蝶云星空聚焦多组织,多利润中心的大中型企业,以 “开放、标准、社交”三大特性为数字经济时代的企业提供开放的 ERP 云平台。服务涵盖:财…...

二叉树的最大深度[简单]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给定一个二叉树root&#xff0c;返回其最大深度。 二叉树的最大深度是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 示例 2&#xff1a…...

[Redis]不同系统间安装redis服务器

日常服务器端开发&#xff0c;消息队列等需求&#xff0c;免不了用到redis&#xff0c;搭建一个redis服务器&#xff0c;方便开发和测试&#xff0c;我们从以下三类系统来说明下&#xff1a; 安装 Redis 服务器的过程因操作系统而异。以下是在常见的 Linux 发行版&#xff08;…...

Unity之动画和角色控制

目录 &#x1f4d5; 一、动画 1.创建最简单的动画 2.动画控制器 &#x1f4d5;二、把动画和角色控制相结合 &#x1f4d5;三、实现实例 3.1 鼠标控制角色视角旋转 3.2 拖尾效果 &#x1f4d5;四、混合动画 最近学到动画了&#xff0c;顺便把之前创建的地形&#xff0…...

C语言库函数实现字符串转大小写

目录 引言 代码 引言 处理字符串时&#xff0c;除了将字符串中的所有大写字母转换为小写字母外&#xff0c;我们还可以利用其他相关函数进行更丰富的文本操作。本文将以一段使用isupper()、tolower()函数实现字符串全转小写的C语言程序为例&#xff0c;详细介绍这两个函数以及…...

hcip----ospf

一&#xff1a;动态路由协议 IGP 协议---RIP OSPF ISIS EIGRP EGP--EGP ---BGP 三个角度的评判一款动态路由协议的优劣 RIP --request response 1.选路--选路依据不好&#xff0c;可能出现环路 2.收敛速度--计时器 3.占用资源-- RIPV1 RIPV2 RIPNG--ipv6 OSPFV1 OSPFV…...

vue中如何写过滤器

全局注册 (可以在main.js中进行全局注册 vue.fifler(test’&#xff0c;function(v){return v0? ‘终止’&#xff1a;v1?进行中:异常 })在组件页面使用 <view>{{state|test}}</view> <script> export default {data(){return {state: 1// state 1 进行中…...

c语言-文件的读写操作(下)

文章目录 前言一、文件的随机读写1.1 fseek()1.2 ftell()1.3 rewind() 总结 前言 本篇文章介绍c语言中文件的随机读写 一、文件的随机读写 1.1 fseek() fseek()函数的作用是根据文件指针的位置和偏移量定位文件指针 int fseek ( FILE * stream, long int offset, int origi…...

android学习笔记----SQLite数据库

用SQLite语句执行&#xff1a; 首先看到界面&#xff1a; 代码如下&#xff1a; MainActivity.java import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.view.View; import android.widget.EditTe…...

开发知识点-Flutter移动应用开发

支持 安卓 IOS Android 鸿蒙 第一章dart基础章节介绍 移动电商——Flutter-广告Banner组件制作 移动电商——Flutter实战课程介绍 Flutter实例——路由跳转的动画效果...

016、气压计原理与高度测量

飞控算法从入门到精通 016 气压计原理与高度测量 一、一次炸机带来的教训 去年夏天,我在一个四轴飞行器上调试定高悬停。气压计用的是MS5611,数据手册翻烂了,滤波算法也上了,地面站里高度曲线看着挺平滑。结果一上天,飞机像喝醉了酒——先是莫名其妙往下掉半米,然后猛…...

雨夜便利店的光,刚好够照亮你这一秒的疲惫

雨声比闹钟更懂你凌晨一点十七分&#xff0c;耳机里循环着一首没名字的 lo-fi beat&#xff0c;窗外的雨没停&#xff0c;也没下大&#xff0c;就那么轻轻敲着空调外机和生锈的铁皮棚。你站在楼道口犹豫要不要出门买泡面&#xff0c;其实不是饿&#xff0c;是心里空了一小块&am…...

【限时解密】ElevenLabs未公开的“Voice Stability Index”(VSI)指标解析——专业级语音稳定性评估体系首度披露

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;【限时解密】ElevenLabs未公开的“Voice Stability Index”&#xff08;VSI&#xff09;指标解析——专业级语音稳定性评估体系首度披露 VSI 的本质与工程意义 Voice Stability Index&#xff08;VSI&…...

云数据中心能效优化:集成资源管理与学习中心管理的实战指南

1. 项目概述&#xff1a;当云计算撞上“能耗墙”&#xff0c;我们如何破局&#xff1f;干了十几年IT&#xff0c;从自建机房到全面上云&#xff0c;我亲眼见证了云计算如何重塑整个行业。它确实像电力网络和公路一样&#xff0c;成了现代社会不可或缺的基础设施。但这些年&…...

半导体行业数据分析:从WSTS报告解读市场趋势与从业者应对策略

1. 从一份行业快报说起&#xff1a;如何解读半导体市场的“水温”早上刚冲好咖啡&#xff0c;习惯性地扫了一眼行业新闻&#xff0c;看到EE Times上这篇关于2013年第一季度全球半导体销售额的简报。标题很直接&#xff1a;“Chip sales up 1% through Q1”。1%的增长&#xff0…...

SLV:用AI对话驱动Solana节点部署与运维的革命性工具

1. 项目概述&#xff1a;SLV&#xff0c;一个为Solana节点管理注入AI灵魂的工具如果你在Solana生态里跑过验证器节点或者搭建过RPC服务&#xff0c;那你一定对下面这套流程不陌生&#xff1a;找一台靠谱的服务器&#xff0c;手动SSH连上去&#xff0c;一行行敲命令安装依赖、编…...

构建自我进化的AI家园:基于多智能体与GitOps的工程实践

1. 项目概述&#xff1a;构建一个能自我进化的AI家园如果你和我一样&#xff0c;对那种“一问一答”式的AI聊天机器人感到厌倦&#xff0c;总想着能不能让AI更“主动”一点&#xff0c;甚至能帮你打理整个技术栈&#xff0c;那么这个项目绝对值得你花时间研究。ai-homebase不是…...

Windows热键侦探:一键定位占用程序,终结快捷键冲突烦恼

Windows热键侦探&#xff1a;一键定位占用程序&#xff0c;终结快捷键冲突烦恼 【免费下载链接】hotkey-detective A small program for investigating stolen key combinations under Windows 7 and later. 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective …...

太秀了,我把自己蒸馏成了 Skill!已开源

最近 GitHub 上掀起了一股「AI 蒸馏」热潮&#xff0c;这里的蒸馏可不是酿酒&#xff0c;而是把身边的人封装成 AI 技能包——同事.skill、老板.skill、搭档.skill 等各类蒸馏项目层出不穷&#xff0c;大家都在把身边人的工作经验、说话风格、做事逻辑&#xff0c;做成可直接使…...

Cursor编辑器配置重置工具:自动化清理与恢复出厂设置

1. 项目概述与核心价值 最近在折腾代码编辑器&#xff0c;特别是像 Cursor 这类深度整合了 AI 能力的 IDE&#xff0c;发现一个挺有意思但容易被忽略的问题&#xff1a; 编辑器配置的“熵增” 。简单来说&#xff0c;就是你用久了之后&#xff0c;各种插件、主题、快捷键、代…...