Protobuf数据格式解析

Protobuf是Google开源的一款类似于Json,XML数据交换格式,其内部数据是纯二进制格式,不依赖于语言和平台,具有简单,数据量小,快速等优点。目前用于序列化与反序列化官方支持的语言有C++,C#, GO, JAVA, PYTHON。适用于大小在1M以内的数据,因为像在移动设备平台,内存是很珍贵。

使用方法也比较简单:

  • 定义用于消息文件.proto
  • 使用protobuf的编译器编译消息文件
  • 使用编译好对应语言的类文件进行消息的序列化与反序列化

先来定义一个简单的消息:

message Person {int32 id = 1;//24string name = 2;//wujingchaostring email = 3;//wujingchao92@gmail.com
}

实际的二进制消息为:

08 18 12 0a 77 75 6a 69 6e 67 63 68 61 6f 1a 16 77 75 6a 69 6e 67 63 68 61 6f 39 32 40 67 6d 61 69 6c 2e 63 6f 6d

下面就讲解这段二进制流数据是怎么组成的:

Varints

一般情况下int类型都是固定4个字节,protobuf定义了一种变长的int,每个字节最高位表示后面还有没有字节,低7位就为实际的值,并且使用小端的表示方法。例如1,varint的表示方法就为:

0000 0001

是不是这样就省了三个字节。

再例如300,4字节表示为:10 0101100,varint表示为:

10101100 00000010

所以前面消息为Person的id的值为00011000,即0x18。

负数的最高位为1,如果负数也使用这种方式表示就会出现一个问题,int32总是需要5个字节,int64总是需要10个字节。

所以定义了另外一种类型:sint32,sint64。采用ZigZag编码,所有的负数都使用正数表示,计算方式:

  • sint32
    (n << 1) ^ (n >> 31)
  • sint64
    (n << 1) ^ (n >> 63)
Signed Original Encoded As
0 0
-1 1
1 2
-2 3
2147483647 4294967294
-2147483648 4294967295

使用Varint编码的类型有int32, int64, uint32, uint64, sint32, sint64, bool, enum。Java里面没有对应的无符号类型,int32与uint32一样。

Wire Type

每个消息项前面都会有对应的tag,才能解析对应的数据类型,表示tag的数据类型也是Varint。

tag的计算方式: (field_number << 3) | wire_type

每种数据类型都有对应的wire_type:

Wire 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

所以wire_type最多只能支持8种,目前有6种。

所以前面Person的id,field_number为1,wire_type为0,所以对应的tag为

1 <<< 3 | 0  = 0x08

Person的name,field_number为2,wire_type为2,所以对应的tag为

2 <<< 3 | 2 = 0x12

对应Length-delimited的wire type,后面紧跟着的Varint类型表示数据的字节数。

所以name的tag后面紧跟的0x0a表示后面的数据长度为10个字节,即"wujingchao"的UTF-8 编码或者ASCII值:

08 18 12 0a 77 75 6a 69 6e 67 63 68 61 6f 1a 16

嵌套的消息类型embedded messages与packed repeated fields也是使用这种方式表示,对应默认值的数据,是不会写进protobuf消息里面的。

packed repeated与repeated的区别在于编码方式不一样,repeated将多个属性类型与值分开存储。而packed repeated采用Length-delimited方式。下面这个是官方文档的例子:

message Test4 {repeated int32 d = 4 [packed=true];
}22        // tag (field number 4, wire type 2)
06        // payload size (6 bytes)
03        // first element (varint 3)
8E 02     // second element (varint 270)
9E A7 05  // third element (varint 86942)

如果没有packed的属性是这样存储的:

20 //tag(field number 4,wire type 0)
03 //first element (varint 3)
20 //tag(field number 4,wire type 0)
8E 02//second element (varint 270)
20 //tag(field number 4,wire type 0)
9E A7 05  // third element (varint 86942)

是不是这种方式比较节省内存,所以proto3的repeated默认就是使用packed这种方式来存储。(proto2与proto3区别在于.proto的语法)。

有了以上的相关概念,我们在读protobuf的源码就比较容易了。

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

protof的描述

首先 protobuf是一个开源项目,是goole内部久经考验的一个东西。主要用于结构化数据串行化的灵活、高效、自动的方法,有如XML,不过他更小,更快,也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。甚至可以在无需重新部署程序的情况下更新数据结构。

protobuf的优点:

1、性能好/效率高

时间开销: XML格式化(序列化)的开销还好;但是XML解析(反序列化)的开销就不敢恭维了。 但是protobuf在这个方面就进行了优化。可以使序列化和反序列化的时间开销都减短。

空间开销:也减少了很多

2、有代码生成机制

比如你你写个一下类似结构体的内容

[cpp] view plaincopy

  1. message testA
  2. {
  3. required int32 m_testA = 1;
  4. }

向写一个这样的机构可以自动生成它的.h 文件和点.cpp文件。  他将对结构体testA的操作封装成一个类。

3、支持向后兼容和向前兼容

当客户端和服务器同事使用一块协议的时候, 当客户端在协议中增加一个字节,并不会影响客户端的使用

4、支持多种编程语言

在Google官方发布的源代码中包含了c++、Java、Python三种语言

protobuf的缺陷

1、二进制格式导致可读性差

为了提高性能,protobuf采用了二进制格式进行编码。这直接导致了可读性差。

2、缺乏自描述

一般来说,XML是自描述的,而protobuf格式则不是。 给你一段二进制格式的协议内容,不配合你写的结构体是看不出来什么作用的。

Protobuf数据格式解析相关推荐

  1. php protobuf 二进制,PHP环境中使用ProtoBuf数据格式

    1.syntax="proto3":表明使用的是proto3格式,如果不指定则为proto2 2.package test:定义包名为test,生成类时,会产生一个目录为test ...

  2. JSON 数据格式解析(转)

    JSON 即 JavaScript Object Natation,它是一种轻量级的数据交换格式,非常适合于服务器与 JavaScript 的交互.本文将快速讲解 JSON 格式,并通过代码示例演示如 ...

  3. android gps磁偏角,GPS数据格式解析

    GPS数据格式解析 简介 GPS发送数据以行为单位,数据格式如下: $信息类型,x,x,x,x,x,x,x,x,x,x,x,x,x 每行以字符"$"开头,以为结尾,CR-Carri ...

  4. 逆向分析某App其Frida、Xposed、Root检测及protobuf数据解析

    1.前言 接到客户需求需要分析某海外语音社交App其房间数据和榜单数据,该app除了部分hook检测外,还有个protobuf挺有意思的,现将该项目的整个流程还原 需要的工具如下: 一个app:链接: ...

  5. Linux下USB抓包工具UsbMon的使用和包数据格式解析

    Linux下USB抓包工具UsbMon的使用和包数据格式解析 一.UsbMon的使用步骤 1.挂载debugfs 2.加载usbmon模块 3.确认usbmon是否可用 4.确认usb设备挂在哪条总线 ...

  6. NTU-RGBD数据集下载及数据格式解析

    下载地址: 0-60:https://drive.google.com/open?id=1CUZnBtYwifVXS21yVg62T-vrPVayso5Hhttps://drive.google.co ...

  7. C语言 JSON数据格式解析

    C语言 JSON数据格式解析 一.如何用c语言编写与解析json数据格式,这篇主要是使用一个第三方的json库,本人已经上传至csdn,下载链接在下方. 二.json库代码文件下载地址(json.ra ...

  8. opendrive数据格式解析思维导图 , opendrive高精地图是自动驾驶领域使用最为广泛的开源高精地图标准级地图格式

    opendrive数据格式解析思维导图 , opendrive高精地图是自动驾驶领域使用最为广泛的开源高精地图标准级地图格式. 本思维导图将详细剖开高精路网地图内部的数据格式,涵盖:道路.车道.车道段 ...

  9. JS逆向-Protobuf逆向解析

    目录 一.python快的解析Protobuf方式 二.什么是Protobuf 三.Protobuf环境配置 四.Protobuf实例序列化与反序列化 五.逆向解析 Protobuf案例 1.pyth ...

最新文章

  1. 非root用户编译安装源码包
  2. PAT甲级1099 Build A Binary Search Tree (30分):[C++题解]建立二叉搜索树、dfs和bfs
  3. 计算机ai听课记录,ai ei ui评课稿听课记录
  4. ora-01033:oracle initializationg or shutdown in progress
  5. Python基础--列表
  6. 7.6~7.20集训总结(一)
  7. android 构造xml,android 中生成xml文件
  8. java 设计模式 优缺点_java设计模式2:原型模式(机制\优缺点分析\使用场景)...
  9. switch 的性能提升了 3 倍,我只用了这一招!
  10. adb 提示:error: unknown host service解决方法
  11. 4007-基于邻接表的新边的增加(C++,附思路)
  12. HDU-2570-迷瘴
  13. WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.
  14. python 消息框架_消息框架message
  15. Yolov2 训练时anchor是如何使用的?build_target
  16. LINUX下载编译lame
  17. 高数18讲_1000题错题总结_第三四讲
  18. 如何压缩pdf文件的大小?
  19. 电脑上最好的5个azw3阅读器
  20. 5月第2周业务风控关注 | 等保2.0将于5月13日正式发布

热门文章

  1. Google 就业岗分析
  2. 三种男性最需要的营养素
  3. 安卓上通过pydorid 3来使用jupyter notebook(鸿蒙/华为/安卓手机/平板进行python编程学习)
  4. ncre二级c语言程序设计,考纲分析:NCRE二级C语言程序设计辅导
  5. autocad ios 虚线_CAD交互绘制虚线(com接口)
  6. Android studio语音识别集成科大讯飞语音转文字
  7. 信息安全竞赛优秀作品介绍1
  8. 回车enter键的js
  9. 计算机系统基础学习笔记(7)-缓冲区溢出攻击实验
  10. 美团网站底部超链接部分设计实现