protocol buffer能够跨平台提供轻量的序列化和反序列化,得益于其平台无关的编码格式,本文就介绍下其中的编码格式。

Varints

在protocol buffer中大量使用到了Varints的编码格式,这是一个可变长度的编码格式用于编码整形数字。
Varint的最小单位是byte,即8位,每byte第一位(msb)是标志位用于标记是否还有后续byte。

  1. ===1===
  2. 0000 0001
  3. ===300===
  4. 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:

  1. repeated int32 int = 1 [packed=true];

这样序列化的数据就成了0A 03 01 02 03,其中0A表示使用不定长编码,之后03表示长度,接下来是数据,就这个例子就能节约1byte。packed只适用于varint或固定长度数值表示的字段,对于string或者嵌套类型不适用,在proto3中支持的类型默认会使用packed。

实例

  1. syntax = "proto2";
  2. message Person {
  3. required string name=1;
  4. required int32 age=2;
  5. repeated Address add=3;
  6. }
  7. message Address{
  8. required string add=1;
  9. }
  10. ---实例---
  11. name: "MyName"
  12. age: 18
  13. add {
  14. add: "MyAdd1"
  15. }
  16. add {
  17. add: "MyAdd2"
  18. }
  19. ---Hex---
  20. 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
  21. ---解释---
  22. 0A //变长类型tag为1的字符串
  23. 06 //name字段6 byte长度
  24. 4D 79 4E 61 6D 65 //MyName
  25. 10 //varint编码tag为2
  26. 12 //
  27. 1A //变长类型tag为3
  28. 08 //Adress 8 byte长度
  29. 0A //变长类型tag为1
  30. 06 //add字段6 byte长度
  31. 4D 79 41 64 64 31 //MyAdd1
  32. 1A //变长类型tag为3
  33. 08 //Adress 8 byte长度
  34. 0A //变长类型tag为1
  35. 06 //add字段6 byte长度
  36. 4D 79 41 64 64 32 //MyAdd2

protocol buffer 编码的更多相关文章

  1. protocol buffer开发指南(官方)

    欢迎来到protocol buffer的开发者指南文档,一种语言无关.平台无关.扩展性好的用于通信协议.数据存储的结构化数据序列化方法. 本文档是面向计划将protocol buffer使用的到自己的 ...

  2. Google Protocol Buffer 的编码方式

    Google Protocol Buffer 使用到了两种编码方式:Varints 和 zigzag. 一 Varints 编码 每个 byte 只用 7bit 表示数字,最高位 bit作为标志位,如 ...

  3. google protocol buffer——protobuf的使用特性及编码原理

    这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们展示了 ...

  4. google protocol buffer——protobuf的编码原理二

    这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们主要通 ...

  5. protocol buffer的高效编码方式

    目录 简介 定义一个简单的message Base 128 Varints 消息体的结构 符号整数 字符串 嵌套的消息 总结 简介 protocol buffer这种优秀的编码方式,究竟底层是怎么工作 ...

  6. 从零开始山寨Caffe·伍:Protocol Buffer简易指南

    你为Class外访问private对象而苦恼嘛?你为设计序列化格式而头疼嘛? ——欢迎体验Google Protocol Buffer 面向对象之封装性 历史遗留问题 面向对象中最矛盾的一个特性,就是 ...

  7. [原创翻译]Protocol Buffer Basics: C#

    Protocol Buffer 基础知识:c#    原文地址:https://developers.google.com/protocol-buffers/docs/csharptutorial   ...

  8. Google Protocol Buffer 的使用和原理[转]

    本文转自: http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/ Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构 ...

  9. 学习Google Protocol buffer之概述

    XML这种属于非常强大的一种格式,能存储任何你想存的数据,而且编辑起来还是比较方便的.致命的缺陷在于比较庞大,在某些情况下,序列化和解析都会成为瓶颈.这种对于实时性很强的应用来说,就不太适合了,想象下 ...

随机推荐

  1. Java Spring MVC 错误 及 常见问题 总结

    [参考]spring入门常见的问题及解决办法 错误: 从Git新获取项目 运行出现 1.org.springframework.beans.factory.BeanDefinitionStoreExc ...

  2. 蜕变成蝶~Linux设备驱动中的并发控制

    并发和竞争发生在两类体系中: 对称多处理器(SMP)的多个CPU 内核可抢占的单CPU系统 访问共享资源的代码区域称为临界区(critical sections),临界区需要以某种互斥机制加以保护.在 ...

  3. Nginx 配置参数详解

    #定义Nginx运行的用户和用户组 user www www;   #nginx进程数,建议设置为等于CPU总核心数. worker_processes 8;   #全局错误日志定义类型,[ debu ...

  4. linux下vi或vim操作Found a swap file by the name的原因及解决方法

    在linux下用vi或vim打开Test.java文件时 [root@localhost tmp]# vi Test.java出现了如下信息: E325: ATTENTION    Found a s ...

  5. PHP 合并有序数组

    <?php //两个有序数组合并 $arr1 = [1,5,7,44,66,89]; $arr2 = [4,5,6,88,99,105,111]; $arr3 = []; $l1 = count ...

  6. 给vscode添加右键打开功能

    将以下文本存为vscode.reg,然后运行: Windows Registry Editor Version 5.00  ; Open files [HKEY_CLASSES_ROOT\*\shel ...

  7. fastadmin 使用记录

    1.引用静态css文件 参考路径:D:\wwwroot\public\assets\addons\cms\css 静态资源文件基本都放在public目录下引用 引用实例 D:\wwwroot\addo ...

  8. springboot 启动的时候报错 Error creating bean with name 'solrClient'

    springboot 启动的时候报错: org.springframework.beans.factory.BeanCreationException: Error creating bean wit ...

  9. webpack使用小记

    前言 webpack是目前前端开发必不可少的一款模块加载器兼构建工具,它能极其方便的处理各种资源的打包和使用, 让前端开发获得与后端开发几乎一致的体验. webpack特点 webpack 是以 co ...

  10. 网站SEO优化问答精选【转载】

    在接触seo的过程中,大家都会碰到很多这样或那样的问题,特别是一些seo新手由于知识有限会经常到很多地方问一些网站优化的问题,做seo时间慢慢变长之后,知识会慢慢地积累,之前的问题也会慢慢的都被解答. ...