protocol buffer 编码
protocol buffer能够跨平台提供轻量的序列化和反序列化,得益于其平台无关的编码格式,本文就介绍下其中的编码格式。
Varints
在protocol buffer中大量使用到了Varints的编码格式,这是一个可变长度的编码格式用于编码整形数字。
Varint的最小单位是byte,即8位,每byte第一位(msb)是标志位用于标记是否还有后续byte。
===1===
0000 0001
===300===
1010 1100 0000 0010
上面300的例子首先读入第一个字节发现第一位为1,表示还有后续byte,然后读取后一个byte,第一位为0就判断已经读完,然后组装数值将其余位数取出0101100 0000010,然后反转并拼接成为000 0010-010 1100,这样就组成了300。
其他类型
负数,sint与int
在protocol buffer的定义中sint和int似乎看上去是重复的,但其实这两种类型的底层编码式不同的。这里以-3为例:
-3使用int编码会变成FD FF FF FF FF FF FF FF FF 01,首先这也是varint编码去掉每个byte的首位标志位然后反转顺序就成了FF FF FF FF FF FF FF FD是-3的补码。
而使用sint编码会变成05,貌似和-3没有关系,其实它是-3经过一个zigzag转换而得来的。
| Signed Original | Encoded As |
|---|---|
| 0 | 0 |
| -1 | 1 |
| 1 | 2 |
| -2 | 3 |
| 2147483647 | 4294967294 |
| -2147483648 | 4294967295 |
这样转换可以大大减少负数的表示长度,所以建议在经常出现负数的地方使用sint而不是int可以缩短编码的大小。
非varient数值
对于double/fixed64,float/fixed32会分别使用固定的64位或32位进行表示。
不定长数据类型
对于string,byte等类型,就使用这种类型,首先使用一个varint表示长度,之后是数据的内容,列入字符串aaa就是03 61 61 61 其中03表示长度为3,61是a的utf8编码。值得注意的是,嵌套的message类型、repeat字段也都是使用这种形式进行编码到对象中的。
message编码
有了上面这些在准备,我们可以进入真正的消息的编码了。protocol buffer中每个字段都是根据定义的tag来进行定位的,在序列化的数据中,每个字段首先是一个Varint用于标记tag,其中最后三位使用来标志该字段的数据类型。
| Type | Meaning | Used For |
|---|---|---|
| 0 | Varint | int32, int64, uint32, uint64, sint32, sint64, bool, enum |
| 1 | 64-bit | fixed64, sfixed64, double |
| 2 | Length-delimited | string, bytes, embedded messages, packed repeated fields |
| 3 | Start group | groups (deprecated) |
| 4 | End group | groups (deprecated) |
| 5 | 32-bit | fixed32, sfixed32, float |
前面的位数用于标志tag,例如0000 1000,去掉第一个标志位后三个类型位,就表示tag为1的字段。
对于repeat类型由于历史原因,proto2中默认是将数组元素并排排列在内的例如[1,2,3]会保存成[08 01 08 02 08 03]。后来对repeat类型进行了改进引入packed在定义的后面加上packed:
repeated int32 int = 1 [packed=true];
这样序列化的数据就成了0A 03 01 02 03,其中0A表示使用不定长编码,之后03表示长度,接下来是数据,就这个例子就能节约1byte。packed只适用于varint或固定长度数值表示的字段,对于string或者嵌套类型不适用,在proto3中支持的类型默认会使用packed。
实例
syntax = "proto2";
message Person {
required string name=1;
required int32 age=2;
repeated Address add=3;
}
message Address{
required string add=1;
}
---实例---
name: "MyName"
age: 18
add {
add: "MyAdd1"
}
add {
add: "MyAdd2"
}
---Hex---
0A 06 4D 79 4E 61 6D 65 10 12 1A 08 0A 06 4D 79 41 64 64 31 1A 08 0A 06 4D 79 41 64 64 32
---解释---
0A //变长类型tag为1的字符串
06 //name字段6 byte长度
4D 79 4E 61 6D 65 //MyName
10 //varint编码tag为2
12 //
1A //变长类型tag为3
08 //Adress 8 byte长度
0A //变长类型tag为1
06 //add字段6 byte长度
4D 79 41 64 64 31 //MyAdd1
1A //变长类型tag为3
08 //Adress 8 byte长度
0A //变长类型tag为1
06 //add字段6 byte长度
4D 79 41 64 64 32 //MyAdd2
protocol buffer 编码的更多相关文章
- protocol buffer开发指南(官方)
欢迎来到protocol buffer的开发者指南文档,一种语言无关.平台无关.扩展性好的用于通信协议.数据存储的结构化数据序列化方法. 本文档是面向计划将protocol buffer使用的到自己的 ...
- Google Protocol Buffer 的编码方式
Google Protocol Buffer 使用到了两种编码方式:Varints 和 zigzag. 一 Varints 编码 每个 byte 只用 7bit 表示数字,最高位 bit作为标志位,如 ...
- google protocol buffer——protobuf的使用特性及编码原理
这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们展示了 ...
- google protocol buffer——protobuf的编码原理二
这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们主要通 ...
- protocol buffer的高效编码方式
目录 简介 定义一个简单的message Base 128 Varints 消息体的结构 符号整数 字符串 嵌套的消息 总结 简介 protocol buffer这种优秀的编码方式,究竟底层是怎么工作 ...
- 从零开始山寨Caffe·伍:Protocol Buffer简易指南
你为Class外访问private对象而苦恼嘛?你为设计序列化格式而头疼嘛? ——欢迎体验Google Protocol Buffer 面向对象之封装性 历史遗留问题 面向对象中最矛盾的一个特性,就是 ...
- [原创翻译]Protocol Buffer Basics: C#
Protocol Buffer 基础知识:c# 原文地址:https://developers.google.com/protocol-buffers/docs/csharptutorial ...
- Google Protocol Buffer 的使用和原理[转]
本文转自: http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/ Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构 ...
- 学习Google Protocol buffer之概述
XML这种属于非常强大的一种格式,能存储任何你想存的数据,而且编辑起来还是比较方便的.致命的缺陷在于比较庞大,在某些情况下,序列化和解析都会成为瓶颈.这种对于实时性很强的应用来说,就不太适合了,想象下 ...
随机推荐
- mysql密码的坑
一段时间没用本机的mysql,忘了root密码,从网上找的修改方法用起来大多都有问题.mysql版本8.0.12. 网上大多数思路:修改msql启动方式为带--skip-grant-tables参数: ...
- 关系数据库(RDBMS)小记
关系数据库三个范式 三个范式: 第一范式(1NF):数据表中的每一列(每个字段)必须是不可拆分的最小单元,也就是确保每一列的原子性 这里说的不可拆分通常是放在业务背景下而言的,是否可拆分视业务需求而定 ...
- python内建时间模块 time和datetime
时间模块 UTC(Coordinated Universal Time,世界协调时)亦即格林威治天文时间,世界标准时间.在中国为UTC+8.DST(Daylight Saving Time)即夏令时. ...
- laravel5.8笔记五:基类控制器和基类模型
建立基类的目的就是为了方便继承.比如:Admin模块访问,是否登陆.检测登陆可以写到基类里面 控制器基类 原始基类:app\Http\Controllers\Controller.php,我们下面要做 ...
- osggeometry修改更新顶点
osg::Geometry *geometry = geode->getDrawable()->asGeometry();geometry->setDataVariance(osg: ...
- SDE表空间不足解决办法(ORA-01653)
一.问题描述 在往空间数据库拷贝数据的时候,发生了ORA-01653的错误,提示信息如下: 这主要是因为表空间不足引起的,出现这种表空间不足的问题一般有两种情况:一种是表空间的自动扩展功能 ...
- JS学习大作业-Excel
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- C# WinForm窗体控件Panel修改边框颜色以及边框宽度方法
C# WinForm窗体控件Panel修改边框颜色以及边框宽度方法 1.新建组件这里可以自定义一个Panel控件起名为PanelEx 2.增加一个BoderColor属性和BoderSize属性 pr ...
- wpgcms---字符串截取
在使用wpgcms做项目的时候,会用到要对描述做字符串截取,具体方法如下: {{ contentInfo.summary|slice(0,75) }}
- [LeetCode] Group Anagrams 群组错位词
Given an array of strings, group anagrams together. Example: Input: ["eat", "tea" ...