protobuf 讲解

一、序列化概念回顾

二、什么是PB

将结构化数据进行序列化的一种方式

三、PB的特点

语言无关、平台无关:即PB支持Java,C++、Python等多种语言。支持多个平台

高效:即比XML更小,更快,更为简单。

扩展性、兼容性好:你可以更新数据结构,而不影响和破坏原有的旧程序。

使用特点:ProtoBuf是需要依赖通过编译生成的头文件和源文件来使用。

四、安装ProtoBuf

ProtoBuf下载地址:https://github.com/protocolbuffers/protobuf/releases

1、在windows安装

配置一下环境变量就可以了

protoc --version 打印出版本

2、在ubuntu下安装

下载依赖器

下载protoBuf

解压包 unzip

编译生成protobuf

一次执行下面的命令 大概需要半个小时左右

这里需要更改profile,修改环境变量

sudo vim /etc/profile

在里面添加下面的内容

#(动态库搜索路径) 程序加载运⾏期间查找动态链接库时指定除了系统默认路径之外的其他路径export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/protobuf/lib/
#(静态库搜索路径) 程序编译期间查找动态链接库时指定查找共享库的路径
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/protobuf/lib/
#执⾏程序搜索路径
export PATH=$PATH:/usr/local/protobuf/bin/
#c程序头⽂件搜索路径
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/local/protobuf/include/
#c++程序头⽂件搜索路径
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/protobuf/include/
#pkg-config 路径
export PKG_CONFIG_PATH=/usr/local/protobuf/lib/pkgconfig/

再执行这个命令:

source /etc/profile

另外需要说一下Centos用户在安装的时候需要用到这个命令

sudo yum install autoconf automake libtool curl make gcc-c++ unzip

五、使用ProtoBuf

使用protobuf,实现一个通讯录项目,一个版本一个版本的实现,从而有效推进protobuf的学习。

快速上手

目的:完整使用PB,学习基本语法。

在快速上手中,我们会编写第一个版本的通讯录1.0。

• 对⼀个联系⼈的信息使⽤PB进⾏序列化,并将结果打印出来。

• 对序列化后的内容使⽤PB进⾏反序列,解析出联系⼈信息并打印出来。

• 联系⼈包含以下信息:姓名、年龄。
通过通讯录1.0,我们便能了解使⽤ProtoBuf初步要掌握的内容,以及体验到ProtoBuf的完整使⽤流程。

步骤一:创建.protobuf

步骤二:进行编译

-I 指定搜索目录

步骤三:

对一个联系人的信息使用PB进行序列化,并将结果打印出来。

对序列化后的内容使用PB进行反序列化,解析出联系人信息并打印出来。

六、proto3语法详解

升级版本的通讯录

• 不再打印联系⼈的序列化结果,⽽是将通讯录序列化后并写⼊⽂件中。

• 从⽂件中将通讯录解析出来,并进⾏打印。
• 新增联系⼈属性,共包括:姓名、年龄、电话信息、地址、其他联系⽅式、备注。

1、字段规则、消息类型的定义和使用

新增联系人的属性。

repeated来定义一个数组。消息中可以包含该字段任意多次(包括零次),其中重复值的顺序会被保留。可以理解为定义了⼀个数组。

singular的规则,消息中可以包含该字段零次或⼀次(不超过⼀次)。proto3语法中,字段默认使⽤该规则。

可以嵌套定义message。

引入 phone文件

定义通讯录proto文件

把通讯录的信息写入文件,首先编写makefile文件。

里面调用的函数返回的是一个已经开辟好的空间所以我们可以使用这个空间直接对contact新增联系人。

查看二进制文件

读取文件

decode的使用

2、proto3语法理解enum类型

0必须存在,必须在第一个。

也可以定义在消息体内

不能让同级的enum类型中的成员系统,多个文件中的enum类型中的类型也不能同名。会编译报错。解决方法:可以包含一个命名空间进行隔离。

通讯录2.1,更新proto文件

设置联系人电话类型

修改打印函数

枚举类型会被默认设置。反序列化时会设置枚举值为0的枚举类型。

3、Any类型的讲解

Any类型可以被理解为是一个泛型类型。可以存储任意的消息类型。

通讯录2.2版本 使用Any字段存放联系人地址。

新增联系人地址

读出联系人地址

4、oneof类型讲解

2.3版本新增其他联系方式

只能设置一个其他联系方式

字段编号不能重复,不能使用repeated来修饰里面的值,

添加联系人的其他联系方式

读取联系人的其他联系方式

5、map类型的使用

2.4版本,增加备注

不能使用repeated来修饰,设置的kv值是无序的

设置联系人备注信息

打印备注信息

6、默认值讲解

反序列化消息时,如果被反序列化的⼆进制序列中不包含某个字段,反序列化对象中相应字段时,就会设置为该字段的默认值。不同的类型对应的默认值不同:

• 对于字符串,默认值为空字符串。
• 对于字节,默认值为空字节。
• 对于布尔值,默认值为false。
• 对于数值类型,默认值为0。
• 对于枚举,默认值是第⼀个定义的枚举值,必须为0。

• 对于消息字段,未设置该字段。它的取值是依赖于语⾔。• 对于设置了repeated的字段的默认值是空的(通常是相应语⾔的⼀个空列表)。

• 对于 消息字段 、 oneof字段 和 any字段 ,C++和Java语⾔中都有has_⽅法来检测当前字段是否被设置。

对于标量数据类型,在proto3语法下,没有生成has_方法。不确定是用户设置的还是一个默认值。

7、更新消息

新增字段

注意不要和老字段冲突即可

修改字段

• 禁⽌修改任何已有字段的字段编号。

• 若是移除⽼字段,要保证不再使⽤移除字段的字段编号。正确的做法是保留字段编号
(reserved),以确保该编号将不能被重复使⽤。不建议直接删除或注释掉字段。

• int32,uint32,int64,uint64和bool是完全兼容的。可以从这些类型中的⼀个改为另⼀个,
⽽不破坏前后兼容性。若解析出来的数值与相应的类型不匹配,会采⽤与C++⼀致的处理⽅案(例如,若将64位整数当做32位进⾏读取,它将被截断为32位)。
• sint32和sint64相互兼容但不与其他的整型兼容。• string和bytes在合法UTF-8字节前提下也是兼容的。

• bytes包含消息编码版本的情况下,嵌套消息与bytes也是兼容的。

• fixed32与sfixed32兼容,fixed64与sfixed64兼容。
• enum与int32,uint32,int64和uint64兼容(注意若值不匹配会被截断)。但要注意当反序
列化消息时会根据语⾔采⽤不同的处理⽅案:例如,未识别的proto3枚举类型会被保存在消息中,但是当消息反序列化时如何表⽰是依赖于编程语⾔的。整型字段总是会保持其的值。
• oneof:

◦ 将⼀个单独的值更改为新oneof类型成员之⼀是安全和⼆进制兼容的。

◦ 若确定没有代码⼀次性设置多个值那么将多个字段移⼊⼀个新oneof类型也是可⾏的。

◦ 将任何字段移⼊已存在的oneof类型是不安全的。

删除字段

不能直接删除已存在的字段,

如果要删除老子段,要保证不使用已经被删除的或者已经被注释掉的字段编号,会导致下列问题

如何不使用已经被注释掉的字段编号呢?

reserved保留项

指定保留的字段编号

会有一个错误发生

还可以这样写

结果:我们看到年龄不在使用前面的字段编号了

上面的生日信息哪里去了呢。被存放到了未知字段中。

未知字段

未知字段是什么?

• 未知字段:解析结构良好的protocolbuffer已序列化数据中的未识别字段的表⽰⽅式。例如,当旧程序解析带有新字段的数据时,这些新字段就会成为旧程序的未知字段。
• 本来,proto3在解析消息时总是会丢弃未知字段,但在3.5版本中重新引⼊了对未知字段的保留机制。所以在3.5或更⾼版本中,未知字段在反序列化时会被保留,同时也会包含在序列化的结果中。

从哪获取未知字段?

通过Reflection类中UnKnowFields()方法获取

打印未知字段

前后兼容性

向前兼容:⽼模块能够正确识别新模块⽣成或发出的协议。这时新增加的“⽣⽇”属性会被当作未 知字段(pb 3.5版本及之后)。
向后兼容:新模块也能够正确识别⽼模块⽣成或发出的协议。
前后兼容的作⽤:当我们维护⼀个很庞⼤的分布式系统时,由于你⽆法同时 升级所有 模块,为了保证 在升级过程中,整个系统能够尽可能不受影响,就需要尽量保证通讯协议的“向后兼容”或“向前兼容”。

8、option选项语法详解

option选项可以影响ProtoBuf的编译属性。用的不太多,所以我们可以用文档看一下就可以了。

七、通讯录4.0实现 --- 网络版

服务器

客户端

客户端调用接口req,调用返回resp。

客户端的.proto文件和服务器的相同

客户端的菜单编写

服务端书写 add del findALL findOne接口。每个接口会有req,resp协议。

序列化req

调用接口

反序列化req 新增一个联系人,持久化存储通讯录

序列化resp

反序列化resp

AddContact方法

protobuf远远比json的序列化和反序列化效率高。json的内存占用比protobuf多一倍。

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

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

相关文章

rabbitMq------客户端模块

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言消费者模块信道管理模块管理的字段提供的接口 信道内存管理连接管理类 前言 在RabbitMQ中,提供服务的是信道,因此在客⼾端的实现中&…

WPF之UI进阶--控件样式与样式模板及词典

WPF的优势之一就是能够更加容易快捷的对窗体和控件的外面进行改造,换句话说,那就是UI设计个性化更加容易。主要是借助了样式、模板及词典来实现的。那么本篇博文就一一对他们进行介绍。 文章目录 一、样式1: 定义样式2: 使用Setter设置属性关于Property和…

Python知识点:如何使用Edge Impulse与Python进行机器学习模型部署

开篇,先说一个好消息,截止到2025年1月1日前,翻到文末找到我,赠送定制版的开题报告和任务书,先到先得!过期不候! 使用Edge Impulse与Python进行机器学习模型部署 在物联网和边缘计算领域&#x…

java线程池参数设置原则

线程池参数设置原则 1 如何为线程池设置合适的线程参数? 目前根据一些开源框架,设置多少个线程数量通常是根据应用的类型**:I/O 密集型、CPU 密集型。** I/O密集型 I/O密集型的场景在开发中比较常见,比如像 MySQL数据库读写、文…

C或C++判断指针是否指向同一块内存

有时需要判断指针是否指同一块内存,例如设计字符串时: (1)insert函数 (2) replace函数 (3)assign函数 难点是迭代器,判断是否同一个迭代器时,需要你在设计迭代器时加…

Kubernetes-环境篇-01-mac开发环境搭建

1、brew安装 参考知乎文章:https://zhuanlan.zhihu.com/p/111014448 苹果电脑 常规安装脚本(推荐 完全体 几分钟安装完成) /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"苹果电脑 极…

Rstudio:强大的R语言集成开发环境(IDE)

Rstudio 应该是 R 语言使用的标配,尽管 Rstudio 的母公司 Posit 推出了新一代的集成开发环境 Positron,但其还处于开发阶段。作为用户不妨让其成熟后再使用,现阶段还是 Rstudio 更稳定。 如果你在生物信息学或统计学领域工作,R语言…

Python | Leetcode Python题解之第455题分发饼干

题目&#xff1a; 题解&#xff1a; class Solution:def findContentChildren(self, g: List[int], s: List[int]) -> int:g.sort()s.sort()m, n len(g), len(s)i j count 0while i < m and j < n:while j < n and g[i] > s[j]:j 1if j < n:count 1i …

uni-app - - - - -vue3使用i18n配置国际化语言

uni-app - - - - -使用i18n配置国际化语言 1. 安装vue-i18n2. 配置文件2.1 创建如下文件2.2 文件配置2.3 main文件导入i18n 3. 页面内使用3.1 template内直接使用3.2 变量接收使用 1. 安装vue-i18n npm install vue-i18n --save2. 配置文件 2.1 创建如下文件 locales文件夹里…

水泵模块(5V STM32)

目录 一、介绍 二、传感器原理 1.尺寸介绍 2.继电器控制水泵电路原理图 三、程序设计 main.c文件 bump.h文件 bump.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 水泵模块(bump)通常是指用于液体输送系统的组件&#xff0c;它负责将水或其他流体从低处提…

PHP常用的超全局变量(8个)

在PHP中&#xff0c;超全局变量是一种特殊的变量类型&#xff0c;它们在全部作用域中始终可用&#xff0c;无需使用global关键字来访问。这些变量提供了在PHP脚本中访问和操作各种数据和环境信息的便捷方式。以下是PHP中常用的8个超全局变量的详细介绍&#xff1a; 1. $GLOBAL…

四.网络层(上)

目录 4.1网络层功能概述 4.2 SDN基本概念 4.3 路由算法与路由协议 4.3.1什么是路由协议&#xff1f; 4.3.2什么是路由算法&#xff1f; 4.3.3路由算法分类 (1)静态路由算法 (2)动态路由算法 ①全局性 OSPF协议与链路状态算法 ②分散性 RIP协议与距离向量算法 4.3.…

【C语言】内存函数的使用和模拟实现

文章目录 一、memcpy的使用和模拟实现二、memmove的使用和模拟实现三、memset的使用四、memcmp的使用 一、memcpy的使用和模拟实现 在之前我们学习了使用和模拟实现strncpy函数&#xff0c;它是一个字符串函数&#xff0c;用来按照给定的字节个数来拷贝字符串&#xff0c;那么问…

Javascript数组研究03_手写实现_fill_filter_find_findIndex_findLast_findLastIndex

6 Array.fill() 6.1 基本介绍 fill() 方法用一个固定值填充一个数组中从起始索引&#xff08;默认为 0&#xff09;到终止索引&#xff08;默认为 array.length&#xff09;内的全部元素。它返回修改后的数组。 fill(value) fill(value, start) fill(value, start, end)输入…

【本地免费】SimpleTex 图像识别latex公式

文章目录 相关教程相关文献安装教程 由于mathpix开始收费了&#xff0c;于是本文将介绍一款目前本地免费的SimpleTex工具 相关教程 【超详细安装教程】LaTeX-OCR 图像识别latex公式&#xff08;开源免费&#xff09;_latex图片识别-CSDN博客 相关文献 SimpleTex主页——致力…

如何在微信小程序中实现分包加载和预下载

如何在微信小程序中实现分包加载和预下载 概述 微信小程序提供了分包加载和预下载功能&#xff0c;这有助于优化应用的加载时间&#xff0c;提升用户体验。本文将详细介绍如何在微信小程序中配置分包加载和预下载。 步骤一&#xff1a;配置分包加载 修改app.json文件&#x…

Dijkstra算法,动态规划和滑动窗口

一&#xff1a;最小花费 题目链接&#xff1a;1928. 规定时间内到达终点的最小花费 - 力扣&#xff08;LeetCode&#xff09; &#xff08;1&#xff09;Dijkstra算法 理解问题&#xff1a;首先&#xff0c;我们需要理解问题的核心是找到一条从城市 0 到城市 n-1 的路径&…

数据结构双向链表和循环链表

目录 一、循环链表二、双向链表三、循环双向链表 一、循环链表 循环链表就是首尾相接的的链表&#xff0c;就是尾节点的指针域指向头节点使整个链表形成一个循环&#xff0c;这就弥补了以前单链表无法在后面某个节点找到前面的节点&#xff0c;可以从任意一个节点找到目标节点…

web笔记

<form method"POST" action"{{ url_for(register) }}"><label for"username">用户名:</label><input type"text" id"username" name"username" required><br><label for"p…

5.3 克拉默法则、逆矩阵和体积

本节是使用代数而不是消元法来求解 A x b A\boldsymbol x\boldsymbol b Axb 和 A − 1 A^{-1} A−1。所有的公式都会除以 det ⁡ A \det A detA&#xff0c; A − 1 A^{-1} A−1 和 A − 1 b A^{-1}\boldsymbol b A−1b 中的每个元素都是一个行列式除以 A A A 的行列式。…