比 Json 还牛的 Protobuf 的编码须知(.proto文件该如何编写)

el/2024/5/21 21:12:14

编码规范:

定义一个 message 消息类型:

字段编号尽量使用 16 (虽然前15个 bytes 浪费了,但好处多多)

syntax = "proto3";message SearchRequest {string query = 1;int32 page_number = 2;int32 result_per_page = 3;
}
  • 文件的第一行指明了我们使用的是 proto3 语法:若不指定该行 protocol buffer 编译器会认为是 proto2 。该行必须是文件的第一个非空或非注释行。
  • SearchRequest 消息定义了三个字段(名称/值对),字段就是每个要包含在该类型消息中的部分数据。每个字段都具有名称和类型 。

保留字段:

在采取彻底删除或注释掉某个字段的方式来更新消息类型时,将来其他用户再更新该消息类型时可能会重用这个字段编号。后面再加载该 .ptoto 的旧版本时会引发好多问题,例如数据损坏,隐私漏洞等。一个防止该问题发生的办法是将删除字段的编号(或字段名称,字段名称会导致在 JSON 序列化时产生问题)设置为保留项 reserved。protocol buffer 编译器在用户使用这些保留字段时会发出警告。

message Foo {reserved 2, 15, 9 to 11;reserved "foo", "bar";
}

默认值:

当解析消息时,若消息编码中没有包含某个元素,则相应的会使用该字段的默认值。默认值依据类型而不同:

  • 字符串类型,空字符串
  • 字节类型,空字节
  • 布尔类型,false
  • 数值类型,0
  • 枚举类型,第一个枚举元素
  • 对于可重复类型字段的默认值是空的( 通常是相应语言的一个空列表 )。
  • 内嵌消息类型,依赖于所使用的编程语言。参考 generated code guide 获取详细信息。

注意一下标量字段,在消息被解析后是不能区分字段是使用默认值(例如一个布尔型字段是否被设置为 false )赋值还是被设置为某个值的。例如你不能通过对布尔值等于 false 的判断来执行一个不希望在默认情况下执行的行为。同时还要注意若一个标量字段设置为默认的值,那么是不会被序列化以用于传输的。

在 proto3 枚举值第一个字段必须是0:

message SearchRequest {string query = 1;int32 page_number = 2;int32 result_per_page = 3;enum Corpus {UNIVERSAL = 0;WEB = 1;IMAGES = 2;LOCAL = 3;NEWS = 4;PRODUCTS = 5;VIDEO = 6;}Corpus corpus = 4;
}

未知字段

未知字段是解析结构良好的 protocol buffer 已序列化数据中的未识别字段的表示方式。例如,当旧程序解析带有新字段的数据时,这些新字段就会成为旧程序的未知字段。

本来,proto3 在解析消息时总是会丢弃未知字段,但在 3.5 版本中重新引入了对未知字段的保留机制以用来兼容 proto2 的行为。在 3.5 或更高版本中,未知字段在解析时会被保留同时也会包含在序列化结果中。

消息类型的更新

如果现有的消息类型不再满足您的所有需求——例如,需要扩展一个字段——同时还要继续使用已有代码,别慌! 在不破坏任何现有代码的情况下更新消息类型非常简单。仅仅遵循如下规则即可:

  • 不要修改任何已有字段的字段编号
  • 若是添加新字段,旧代码序列化的消息仍然可以被新代码所解析。应该牢记新元素的默认值以便于新代码与旧代码序列化的消息进行交互。类似的,新代码序列化的消息同样可以被旧代码解析:旧代码解析时会简单的略过新字段。参考未知字段获取详细信息。
  • 字段可被移除,只要不再使用移除字段的字段编号即可。可能还会对字段进行重命名,或许是增加前缀 OBSOLETE_,或保留字段编号以保证后续不能重用该编号。

知识点:

field:message由一个个字段组成,一个字段的完整的二进制描述即<<编号,传输类型>,值>通常称为一个field,如下图。
在这里插入图片描述

  1. proto 是根据字段编号 (field_number) 进行序列化的而不是根据 key,即字段编号代表该字段在序列化时二进制字节流的顺序位置,所以在 grpc 的 service 端和 client 端的 proto 字段编码必须相同
  2. 在对一条消息(message)进行编码的时候是把该消息中所有的key-value对序列化成二进制字节流;key和value分别采用不同的编码方式
  3. 消息的二进制格式只使用消息字段的字段编号(field_num)作为Tag(key/键)的一部分,字段名和声名类型只能在解析端通过引用参考消息类型的定义(即.proto文件)才能确定。
  4. 解码的时候解码程序(解码器)读入二进制的字节流,解析出每一个key-value对;如果解码过程中遇到识别不出来的filed_num就直接跳过。这样的机制保证了即使该消息(message)添加了新的字段,也不会影响旧的编/解码程序正常工作。

http://www.ngui.cc/el/5277791.html

相关文章

Springboot 的三种注入方式对比

首先来看看 Spring 中的实例该如何注入&#xff0c;总结起来&#xff0c;无非三种&#xff1a; 属性注入set 方法注入构造方法注入 我们分别来看下。 1、属性注入 属性注入是大家最为常见也是使用最多的一种注入方式了&#xff0c;代码如下&#xff1a; Service public cl…

SELECT 语句的执行过程

SELECT 语句的执行过程为&#xff1a;连接、查询缓存、词法分析&#xff0c;语法分析&#xff0c;语义分析&#xff0c;构造执行树&#xff0c;生成执行计划、执行器执行计划&#xff0c;下面开始梳理一次完整的查询流程&#xff1a; 连接器 连接器负责与客户端建立连接,获取…

Unity3D 旧版Animation. Time.timeScale = 0暂停,播放动画.

需要用到Time.timeScale 0暂停&#xff0c;但个别地方需要播放动画&#xff0c;在Time.timeScale 0前&#xff0c;开启下面的"播放动画"协程即可. IEnumerator PlayAnimation(Animation animation, string clipName, bool useTimeScale, System.Action onComplete…

C# 计算文件、字符串的MD5值

/// <summary> /// 计算字符串的MD5值 /// </summary> public static string md5(string source) {MD5CryptoServiceProvider md5 new MD5CryptoServiceProvider();byte[] data System.Text.Encoding.UTF8.GetBytes(source);byte[] md5Data md5.ComputeHash(dat…

Unity ParticleSystem 控制粒子移动到一个点,沿路径移动.

一、粒子移动到一个点. 方案1&#xff1a;粒子系统模拟空间为Local. private Transform m_Transform;private ParticleSystem m_ParticleSystem;private ParticleSystem.Particle[] m_particles;public Transform target_Trans; //目标位置.(手动拖拽)private Vector3 pos; …

Unity 贝塞尔曲线(Beizer curve)的原理与运用

前言&#xff1a;现在使用各种搜索引擎 搜索贝塞尔曲线&#xff0c;都会有很多介绍。这里自己写一篇博客&#xff0c;只是记录一下自己的学习过程与运用方法&#xff0c;方便后续回忆。 贝塞尔曲线原理 1、一阶贝塞尔曲线&#xff1a; 一阶贝塞尔曲线&#xff0c;其实就是找一…

IEnumerator、IEnumerable的理解

请直接看以下代码&#xff0c;用foreach来了解Ienumerator和IEnumerable的原理。 class Program{static void Main(string[] args){//1.int[] array_Int;array_Int new int[] { 1, 3, 2 };foreach (int item in array_Int){Console.WriteLine(item);}//2.int[] array_Int2;arr…

Unity 限制物体旋转角度的坑

按我的理解&#xff0c;在Unity中&#xff0c;角度在内部应该是用四元数表示的&#xff0c;所以&#xff0c;在Inspector面板展示的和实际打印出来的localEulerAngles值是不一样的。 直接上代码. /// <summary>/// 旋转值 数值规范.(-180——0——180)/// </summary&…

Unity 使用代码生成饼状图 PieChart

前言&#xff1a; 之前工作需要实现饼状图&#xff0c;这里记录一下用代码生成饼状图的方法. 最终效果如图 原理&#xff1a; 1.原理很简单&#xff0c;通过创建网格绘制各个饼状图基块&#xff0c;然后按角度合成即可. 2.如何创建网格&#xff0c;请直接看官方文档. 3.图像分…

Unity UGUI ScrollView无限滚动效果

一、发现需求 1、在UGUI中&#xff0c;使用 ScrollView 表格布局和字段自适应组件 就可以很好的实现列表功能。 2、如果列表中同时存在很多个Item时&#xff0c;显示区域却只显示一部分&#xff0c;就会造成性能不必要的浪费。 3、这时就想到&#xff0c;利用对象池相关知识…