介绍protobuf编码格式。

protobuf是一种数据交换格式,又称PB编码,由Google开源,类似于Json、XML,但其内部是纯二进制格式,比Json,XML等格式要更精炼,主要用于数据的序列化和反序列化,目前官方提供了JAVA、Python、C++等多种语言的实现。

PB格式的解析依赖于消息文件,在其实现中,.proto定义了各个消息项的id值。

直观地,PB编码就是将一个结构体的内容编码成二进制流。例如一段json数据:

{

"id":176,

"age":24,

"name":"xieyifenxi",

}

.proto文件的定义如下:

message Person {

required int32 id = 1;

optional int32 age = 2;

required string name = 3;

}

则json数据编码成PB格式则是:

08 b0 01 10 18 1a 0a 78 69 65 79 69 66 65 6E 78 69

通常,在协议解析的过程中碰到的PB编码,是没有.proto文件的,解析的时候,只需要根据数据内容,解析出每一项内容即可,而每一项内容的含义,一般通过分析得到。

在许多APP的数据流中,都会存在protobuf编码。本文将通过对PB编码进行介绍,使大家了解如何在协议分析过程中对其进行解析。

01

数据结构

通过前面的例子,可以看到PB的数据结构就是每项数据独立编码,包含一个表示数据类型wire_type和字段序号field_number的数据头,和对应的数据段内容。即HEAD1+MSG1+HEAD2+MSG2+……

在数据头中,字段的序号field_number在整个数据结构中是唯一的,并且可以乱序、缺失和嵌套,序号是在.proto文件中定义的,协议分析中关心的意义不是很大。

数据类型wire_type则表示数据段内容是什么类型,在protobuf官网上描述了类型的含义:

https://developers.google.com/protocol-buffers/docs/encoding

常见的数据类型wire_type为02,分别为Varint类型和Length-delimited变长度数据类型,掌握了这两个类型,基本上在协议解析中,处理PB编码就基本没有障碍了。Varint类型一般就是int数据,而Length-delimited变长度数据类型通常就是字符串数组等数据。

数据头中数据类型和字段序号的组合方式是:(field_number << 3) | wire_type

当然,field_number是Varint类型,需遵循Varint的编码规则。

例如,文首的例子中,id、age、name对应的编码值为:

1 <<< 3 | 0 =0x08

2 <<< 3 | 0 = 0x10

3 <<< 3 | 2 = 0x1a

数据头之后,是数据段,它包含了被编码的数据,不同类型的数据编码格式不同,后面的章节将介绍对应具体类型的编码方法。

02

Varint

Varint是一种对数字进行编码的方法,将数字编码成不定长的二进制数据,数值越小,编码后的字节越少。

编码规则如下:

每个字节的最高位表示下一字节是否仍然是编码的内容,若最高位为1,则下一字节仍然是编码的数字的一部分,若该位为0,则编码到本字节结束。每个字节的后7位,则由小端表示的数字的二进制值,在高位补0凑齐7的倍数位组成。

例如,数值345,其二进制值为 1 0101 1001,在高位补0后分成两个7位 000 0010和 101 1001,则Varint编码结果为:

1 101 1001 0 000 0010

即0xD9 0x02

对文首的例子,由于id 176的二进制值为1011 0000,每七位编码成一个字节,因此,需要用两个字节来表示:

1011 0000 0000 0001

即0xB0 0x01

而age 24的二进制值为 1 1000,则只需要一个字节来表示:

0001 1000

即0x18

前面只是弄明白了int32的Varint编码,对协议解析来说,一般已经够用了,除非这个被编码的数,在取出后需要用其特定的含义来进行计算,因为在PB编码中,还考虑了对负数进行Varint编码。

当我们按照同样的逻辑对负数进行Varint编码时,会发现,负数编码后占用的字节会很多,这不太合算,因此ZigZag编码在PB中被使用,使得Varint编码可以用较少的位数来对负数进行编码。

PB编码中提供了sint32和sint64类型,使用ZigZag编码,让所有的负数都使用正数表示,计算方式如下:

sint32:

(n << 1) ^ (n >> 31)

sint64:

(n << 1) ^ (n >> 63)

即:

原始值0,通过计算,得到ZigZag表示值为0;

原始值-1,通过计算,得到ZigZag表示值为1;

原始值1,通过计算,得到ZigZag表示值为2;

原始值-2,通过计算,得到ZigZag表示值为3;

原始值2147483647,通过计算,得到ZigZag表示值为4294967294;

原始值-2147483648,通过计算,得到ZigZag表示值为4294967295。

依此类推

在协议还原中,对一个Varint编码的值,想要知道它表达的是int32,还是sint32,就只有想办法找到其对应的.proto文件才可以。

03

Length-delimited

Length-delimited就是对可变长度的数据,在编码时,将长度和数据编码在一起,类似于TLV结构的LV部分,前面为数据长度,后面为由数据长度决定的数据内容,数据长度采用的是Varint编码。

例如文首的例子里,name的值为"xieyifenxi"的长度为10,则编码为:

0a 78 69 65 79 69 66 65 6E 78 69

其中,0x0a为长度值的Varint编码,之后紧接着的是值的内容。

这相当的简单。


对protobuf编码的详解就介绍到这里了,有疑问,可以联系我,或者上其官网了解。它的官网是https://developers.google.com/protocol-buffers/

长按进行关注。

ProtoBuf格式详解相关推荐

  1. Java字节码(.class文件)格式详解(一)

    原文链接:http://www.blogjava.net/DLevin/archive/2011/09/05/358033.html 小介:去年在读<深入解析JVM>的时候写的,记得当时还 ...

  2. php serialize取值,PHP 序列化(serialize)格式详解

    PHP 序列化(serialize)格式详解(转) 1.前言 PHP (从 PHP 3.05 开始)为保存对象提供了一组序列化和反序列化的函数:serialize.unserialize.不过在 PH ...

  3. php serialize mysql_php 序列化(serialize)格式详解

    1.前言 PHP (从 PHP 3.05 开始)为保存对象提供了一组序列化和反序列化的函数:serialize.unserialize.不过在 PHP 手册中对这两个函数的说明仅限于如何使用,而对序列 ...

  4. 三维重建:PNG格式详解-与LibPNG使用

    PNG图像包含了骨骼信息,左边的图像比右边的大几十K,包含了骨骼信息:        PNG格式详解:https://blog.mythsman.com/post/5d2d62b4a2005d7404 ...

  5. 4-4:TCP协议之TCP头部格式详解

    文章目录 一:TCP头部格式详解 (1)4位首部长度 (2)序列号和确认应答号 A:可靠性问题 B:32位序号和确认号 (3)窗口大小 (4)标志位 (5)紧急指针 A:带外数据(out_of _ba ...

  6. PHP 序列化(serialize)格式详解

      1.前言 PHP (从 PHP 3.05 开始)为保存对象提供了一组序列化和反序列化的函数:serialize.unserialize.不过在 PHP 手册中对这两个函数的说明仅限于如何使用,而对 ...

  7. 安卓camera2 API获取YUV420_888格式详解

    安卓音视频开发中的一个环节是摄像头采集数据,Android平台上摄像头采集的API有两套,camera1和camera2.本文主要讲的是camera2这套API采集数据,并指明YUV420_888格式 ...

  8. Gerber 格式详解

    Gerber 格式详解 gerber中文 gerber,gerber 文件:590m.com/f/25127180-487459253-79168e(访问密码:551685) 以下内容无关: ---- ...

  9. BMP格式详解<转>

    BMP格式详解 BMP文件格式详解(BMP file format) BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Win ...

最新文章

  1. JVM结构、GC工作机制详解
  2. Python练习题 001:4个数字求不重复的3位数
  3. python读取上一级文件夹下的图片
  4. Asp.net MVC中使用Razor Generator实现View的单元测试
  5. typeorm_如何评价TypeORM?
  6. 你碰到过的最难调的 Bug 是什么?
  7. SpringCloud Stream操作消息队列
  8. 详解如何实现斗鱼、B站等全局悬浮窗直播小窗口
  9. roboware studio安装
  10. 国内最大最专业最活跃的前十大FPGA论坛社区网站精选
  11. Matlab:数组索引
  12. 魔兽争霸如何修改快捷键
  13. 应试教育——人性的扼杀
  14. PTA 10-99 3-1-(b) 查询st1制片公司的总裁
  15. 万字长文|大数据学前准备之Linux入门笔记(附资料)
  16. 7-1 循环-Fibonacci数列的运算 (50 分)
  17. 基于JAVA自行车租借管理系统计算机毕业设计源码+系统+lw文档+部署
  18. C# 阿里云短信接口调用(不使用SDK,单文件完成)
  19. Wormhole流程搭建踩坑总结(一)
  20. discuz3.4安装php,Discuz!X3.4论坛源码下载 及 全新安装教程

热门文章

  1. 轮播切换_javascript基础(一)——轮播图
  2. 微信小程序多项选择器_微信小程序三级联动之多列选择器
  3. 数据结构,堆和栈和队列的概念
  4. 04- CoreData轻量级版本的迁移
  5. 使用hql动态创建对象问题
  6. (转)如何修改maven的默认jdk版本
  7. 《理解 OpenStack + Ceph》---来自-[爱.知识]-推荐
  8. shell之冒号的作用
  9. LINUX环境下资源下载中文目录及中文文件名称问题
  10. Vsftp 安装配置(转)