protobuf 编码原理

简介

Protocol Buffers(protobuf),它是 Google 开发的一种数据序列化协议(与 XML、JSON 类似)。

优点:

  1. 效率高:Protobuf 以二进制格式存储数据,比如 XML 和 JSON 等文本格式更紧凑,也更快。序列化和反序列化的速度也很快。
  2. 跨语言支持:Protobuf 支持多种编程语言,包括 C++、Java、Python 等。
  3. 清晰的结构定义:使用 protobuf,可以清晰地定义数据的结构,这有助于维护和理解。
  4. 向后兼容性:你可以添加或者删除字段,而不会破坏老的应用程序。这对于长期的项目来说是非常有价值的。

缺点:

  1. 不直观:由于 protobuf 是二进制格式,人不能直接阅读和修改它。这对于调试和测试来说可能会有些困难。
  2. 缺乏一些数据类型:例如没有内建的日期、时间类型,对于这些类型的数据,需要手动转换成可以支持的类型,如 string 或 int。
  3. 需要额外的编译步骤:你需要先定义数据结构,然后使用 protobuf 的编译器将其编译成目标语言的代码,这是一个额外的步骤,可能会影响开发流程。

编码原理

举例

对于 protobuf 它的编码是很紧凑的,我们先看一下 message 的结构,举一个简单的例子:

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

message 是一系列键值对,编码过之后实际上只有 tag 序列号和对应的值,这一点相比我们熟悉的 json 很不一样,所以对于 protobuf 来说没有 .proto 文件是无法解出来的:

对于 tag 来说,它保存了 message 字段的编号以及类型信息,我们可以做个实验,把 name 这个 tag 编码后的二进制打印出来:

func main() {student := student.Student{}student.Name = "t"marshal, _ := proto.Marshal(&student)fmt.Println(fmt.Sprintf("%08b", marshal)) // 00001010 00000001 01110100
}


打印出来的结果是这样:

上图中,由于 name 是 string 类型,所以第一个 byte 是 tag,第二 byte 是 string 的长度,第三个 byte 是值,也就是我们上面设置的 “t”。


tag

我们下面先看看 tag:

tag 里面会包含两部分信息:字段序号,字段类型,计算方式就是上图的公式。

① 第一个 bit 是标记位,表示是否字段结尾,这里是 0 表示 tag 已结尾,tag 占用 1byte;
② 接下来 4 个 bit 表示的是字段序号,这里0001 表示序号1。 所以范围 1 到 15 中的字段编号只需要 1 bit 进行编码



做个实验看看,将 tag 改成 16:

protobuf 是小端编码的,需要转成大端方便阅读:

由上图所示,
① 和 ③Tag的每个 byte 第一个 bit 表示是否结束,0 表示结束,所以上面 tag 用两个 byte 表示。

⑤ 去掉每个 byte 第一个 bit 之后,后三位( 0 1 0)表示类型,是 1,

② ④ 其余位是字段序号 (0 0 0 0 0 0 1 0 0 0 0) 表示 16。

所以从上面编码规则我们也可以知道,字段尽可能精简一些,字段尽量不要超过 16 个,这样Tag 就可以用一个 byte 表示了。

同时我们也可以知道,protobuf 序列化是不带字段名的,所以如果客户端的 proto 文件只修改了字段名,请求服务端是安全的,服务端继续用根据序列编号还是解出来原来的字段。但是需要注意的是不要修改字段类型。


类型

类型,protobuf 共定义了 6 种类型,其中两种是废弃的:

ID

Name

Used For

0

VARINT

int32, int64, uint32, uint64, sint32, sint64, bool, enum

1

I64

fixed64, sfixed64, double

2

LEN

string, bytes, embedded messages, packed repeated fields

3

SGROUP

group start (deprecated)

4

EGROUP

group end (deprecated)

5

I32

fixed32, sfixed32, float

上面的例子中,Name 是 string 类型所以上面 tag 类型解出来是 010 ,也就是 2。

参考:数据序列化工具Protobuf编码&避坑指南-腾讯云开发者社区-腾讯云

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

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

相关文章

Swift中的条件语句

在Swift中,条件语句用于根据条件的真假来执行不同的代码块。Swift提供了以下几种条件语句: if语句: if语句根据一个条件来执行代码块。如果条件为真,执行if代码块中的内容;如果条件为假,则跳过if代码块。 语…

同一个类中,对于@Transactional注解的方法调用,事务传播行为不会生效

Service public class MyService { Transactional public void methodA() { // some database operations methodB(); } Transactional(propagation Propagation.REQUIRES_NEW) public void methodB() { // some other database operations } }这里,即使…

基于机器学习的安全检测 网络入侵检测概述

1.概述 入侵检测是网络安全中的经典问题,入侵是指攻击者违反系统安全策略,试图破坏计 算资源的完整性、机密性或可用性的任何行为。由定义可见,入侵并非一种特定的入侵行 为,而是一类入侵行为的统称。常见的网络攻击方式包括拒绝服务攻击、伪装身份入侵等。 入侵检测系统(Intru…

C++这个编程语言以后会消失吗,就像以前70后学的编程语言?

随着AI自举编程的到来,绝大多数人类编程语言都会消失,只有 Scratch 这类启智语言作为儿童玩具保留下来。目前看来这一天不远了。 AI自举编程首先无需遵循这种可读文本变为二进制操作码的套路,它本身就是二进制的。而后,一旦智能制…

全局视角观看Python备忘录-英文版

全局视角观看Python备忘录-英文版

如何使用spring-AI?

Spring AI 简介 1、概览 Spring 通过 Spring AI 项目正式启用了 AI(人工智能)生成提示功能。本文将带你了解如何在 Spring Boot 应用中集成生成式 AI,以及 Spring AI 如何与模型互动。 2、Spring AI 的主要概念 首先回顾一下一些关键…

Qt中的槽(slot)和机器视觉的算子(operator)

Qt中的槽(slot)和机器视觉中的算子(operator)都是方法或函数,它们都是在软件中用于执行特定任务的代码块。 在Qt中,槽是一段可以被信号触发的代码,用于响应特定的事件。槽是对象的一部分&#…

十分钟搞定4G转Uart网关:FlexLua低代码助力

在当今的物联网应用中,各种设备之间的连接变得日益重要,而4G转Uart网关设备的出现为设备之间的通信提供了简便的解决方案,推动了物联网技术的不断发展。 4G转Uart网关的通信原理相对简单清晰。它通过4G网络接收数据,然后将数据转换…

Nginx内存池相关源码剖析(六)外部资源释放和内存池销毁

ngx_destroy_pool函数 先执行回调函数释放所有的外部资源,然后free释放所有的大块内存和小块内存。 // 释放外部资源,销毁内存池 void ngx_destroy_pool(ngx_pool_t *pool) {ngx_pool_t *p, *n;ngx_pool_large_t *l;ngx_pool_cleanup_t *…

电脑录制视频软件推荐,帮你找到合适的那一款

随着科技的不断发展,录制视频已成为人们在学习、工作和生活中不可或缺的一部分。电脑录制视频软件作为实现这一目标的重要工具,已经越来越受到用户的青睐。本文将详细介绍三种常用的电脑录制视频软件,帮助用户更好地理解和使用这些工具&#…

大文件上传分片合并java并发开发要点

前面介绍过大文件上传分片合并的nodejs并发示例,主要有mapLimit、Promise、pipeline、fs.createReadStream、fs.createWriteStream(注意,这个设置写入偏移量)等要点,可以实现将文件分片并发写入目标文件的。 java的话,不太熟悉去搜…

高负压采样器

你的未来是你自己创造的,你的路是你自己选择的。走向成功,需要你的勇气和决心,成功不是得到多少,而是付出了多少。当你还在努力时,不要忘记身边的风景——鹤壁永成在你身边 一、高负压瓦斯采取器的用途: 高…

Springboot的配置文件详解:从入门到精通(二)

本系列文章简介: Spring Boot是一种用于构建Java应用程序的开发框架,它提供了一种简化的方式来快速搭建和部署应用程序。在Spring Boot中,配置文件是一种重要的工具,用于配置应用程序的行为和属性。配置文件可以包含各种配置选项&…

MS SQL Server partition by 函数实战 统计与输出

目录 需求 范例运行环境 表及视图样本设计 数据统计实现 小结 需求 假设有一课程项目,我们需要统计该项目中的课件数量,并提取课程信息,如课程标题名称、排序号等,如果使用 GROUP BY 聚合函数,则只能统计返回课件…

Java集合进阶——泛型

1.泛型 介绍&#xff1a; 泛型可以在编译阶段约束操作的数据类型&#xff0c;并进行检查。 应用场景&#xff1a; 如果在定义类、方法、接口的时候&#xff0c;如果类型不确定&#xff0c;就可以使用泛型。 格式&#xff1a; <数据类型> 注意&#xff1a; 泛型只支持引…

数字化社交的引擎:解析Facebook的影响力

Facebook&#xff0c;作为全球最大的社交媒体平台&#xff0c;已经深深地融入了我们的日常生活和文化中。它不仅仅是一个简单的社交工具&#xff0c;更是一个复杂的数字生态系统&#xff0c;影响着我们的社交模式、文化认同以及信息获取方式。在这篇文章中&#xff0c;我们将深…

【华为】Telnet实验配置

【华为】Telnet 实验配置 应用场景三种认证方式配置注意事项拓扑无认证&#xff08;None&#xff09;交换机配置顺序Telnet ServerTelnet Client测试 密码认证&#xff08;Password&#xff09;配置顺序Telnet ServerTelnet Client测试 AAA认证&#xff08;scheme&#xff09;配…

C语言经典例题[24]

文章目录 1.字符串左旋结果2.offsetof宏的实现3.模拟实现atoi4.n的k次方5.字符串逆序 1.字符串左旋结果 题目内容&#xff1a;写一个函数&#xff0c;判断一个字符串是否为另外一个字符串旋转之后的字符串。 例&#xff1a;给定s1 AABCD和s2 BCDAA,返回1 给定s1 abcd和s2…

使用TomCat在idea写一个可以实现分页查询的前后端学生项目04.12

使用TomCat在idea写一个前后端学生项目04.12项目包-CSDN博客 在前端界面需要引入的插件&#xff1a; 在该网站下载需要的插件 Maven Repository: Search/Browse/Explore (mvnrepository.com)https://mvnrepository.com/ 分页查询&#xff1a; 在前端jsp页面使用c:forEach c:…

WordPress 多站点切换域名完整指南:详细步骤和注意事项

因为公司的需要&#xff0c;需要对 WordPress 多站点进行域名切换, 一开始我也找了相关的方案和教程&#xff0c;但是很可惜&#xff0c;国内这一块网上的资料几乎为0&#xff0c;所以我把实现的过程写了一篇文章分享出来&#xff0c;为后来的人铺路。 开始之前&#xff0c;先…