protobuf编码
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化,适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
字段规则
required: 字段必须存在optional: 字段没有或有一个repeated: 字段重复,0个或多个
proto 数据类型
|
.proto Type
|
Notes
|
C++ Type
|
Java Type
|
Python Type[2]
|
Go Type
|
|---|---|---|---|---|---|
| double | 固定8字节长度 | double | double | float | *float64 |
| float | 固定4字节长度 | float | float | float | *float32 |
| int32 | 可变长度编码。对负数编码低效,如果字段可能是负数,用sint32代替 | int32 | int | int | *int32 |
| int64 | 可变长度编码。对负数编码低效,如果字段可能是负数,用sint64代替 | int64 | long | int/long[3] | *int64 |
| uint32 | 可变长度编码,无符号整数 | uint32 | int[1] | int/long[3] | *uint32 |
| uint64 | 可变长度编码,无符号整数 | uint64 | long[1] | int/long[3] | *uint64 |
| sint32 | 可变长度编码。有符号整数。 These more efficiently encode negative numbers than regular int32s. | int32 | int | int | *int32 |
| sint64 | 可变长度编码。有符号整数。These more efficiently encode negative numbers than regular int64s. | int64 | long | int/long[3] | *int64 |
| fixed32 | 固定4字节长度,无符号整数。 More efficient than uint32 if values are often greater than 228. | uint32 | int[1] | int/long[3] | *uint32 |
| fixed64 | 固定8字节长度,无符号整数。 More efficient than uint64 if values are often greater than 256. | uint64 | long[1] | int/long[3] | *uint64 |
| sfixed32 | 固定4字节长度,有符号整数 | int32 | int | int | *int32 |
| sfixed64 | 固定8字节长度,有符号整数 | int64 | long | int/long[3] | *int64 |
| bool | bool | boolean | bool | *bool | |
| string | UTF-8 encoded or 7-bit ASCII text. | string | String | str/unicode[4] | *string |
| bytes | 包含任意字节序列 | string | ByteString | str | []byte |
编码规则
1.varints
理解简单protobuf编码,首先要知道varints。varints使用一个字节或多个字节对整数序列化方法。
varints中的每个字节除了最后一个字节,有一个最有效位(most significant bit ,msb),这意味指示之后有其他字节。每个字节的低7位一组数的补码
例如:
1
0000 0001
300
1010 1100 0000 0010
只取每个字节低七位
010 1100 000 0010
小端序->大端序
000 0010 010 1100 --> 0001 0010 1100 =300
2.消息结构
protobuf 消息是一系列key-value对,对于二进制消息,字段数字作为关键字。字段的命名和类型在解码时确定。
在进行消息编码时,key/value被连接成字节流。在解码时,解析器可以直接跳过不识别的字段,这样就可以保证新老版本消息定义在新老程序之间的兼容性,从而有效的避免了使用older消息格式的older程序在解析newer程序发来的newer消息时,一旦遇到未知(新添加的)字段时而引发的解析和对象初始化的错误。最后,我们介绍一下字段标号和字段类型是如何进行编码的。每一个 wire-format消息的key实际上是有两个值组成:proto文件中定义的字段标号和wire type。
|
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 |
key = (field_number << 3) | wire_type key的最后3个bits用于存储字段的类型信息。那么在使用该编码时,Protocol Buffer所支持的字段类型将不会超过8种。
例如:150(十进制) 在protobuf二进制文件中是 08 96 01
08 --> 00001000 field_number=1,wire_type=0
96 01 -> 1001 0110 0000 0001 --> 001 0110 000 0001 --> 000 0001 001 0110 --> 1001 0110 =150
3.Signed Integers
wire_type=0 的类型都以varint 进行编码,所以对于int32和int64,对于负数使用补码,int32 需要5个字节,int64需要10个字节,有符号整数使用ZIgZag编码
ZigZag 将有符号整数映射到无符号整数,以此得到一个绝对值较小的数字(例如-1)j就可以获得一个较小的varint编码值。
|
Signed Original
|
Encoded As
|
|---|---|
| 0 | 0 |
| -1 | 1 |
| 1 | 2 |
| -2 | 3 |
| 2147483647 | 4294967294 |
| -2147483648 | 4294967295 |
sint32: (n << 1) ^ (n >> 31)
sint64: (n << 1) ^ (n >> 63)
4.Non-varint Numbers
wire-type=1:fixed64, sfixed64, double 固定64bit
wire-type=5:fixed32, sfixed32, float,固定32bit
5.Strings
wire-type=2,字符串长度使用varint编码
例如
message Test2 {
optional string b = 2;
}
b=“testing” ,编码后结果:
12 07 74 65 73 74 69 6e 67
12: field number=2,wire-type=2 (2<< 3)|2=0x12
长度为7 varint编码 0x07
74 65 73 74 69 6e 67 UTF8 编码
6.Embedded Messages嵌套消息
wire-type=2
message Test1 {
optional int32 a = 1;
}
message Test3 {
optional Test1 c = 3;
}
Test1's a field set to 150
Test3 编码结果: 1a 03 08 96 01
1a: field_number=3,wire_type=2 (3<< 3)|2=11010=0x1a
03: 字节数
08 96 01 : c编码结果
7.Optional And Repeated Elements
proto2 :消息被定义repeated (没有 [packed=true]选项),编码的消息有0或多个使用相同字段标号的key-value对,这些重复的值不必连续出现; 他们可能会与其他字段交错,但在解码时顺序保留
optional字段,编码后的消息可能有也可能没有包含该字段号的键值对。
proto3 使用packed encoding:
包含零个元素的打包重复字段不会出现在编码消息中。这个字段的所有元素都打包到一个wire-type=2的key-value对中
message Test4 {
repeated int32 d = 4 [packed=true];
}
22 // key (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) proto2默认不设置 packed=true
repeated编码采用空格(0x20)分隔
结果是20 03 20 8e 02 20 9e a7 05
protobuf编码的更多相关文章
- protobuf 编码实现解析(java)
一:protobuf编码基本数据类型 public enum FieldType { DOUBLE (JavaType.DOUBLE , WIRETYPE_FIXED64 ), FLOAT (Java ...
- go protobuf 编码与解码
package main import ( "encoding/hex" "fmt" "github.com/golang/protobuf/prot ...
- protobuf中的编码规则
protobuf中的编码规则 (1)序列化和反序列化: 在开始本部分的内容之前,首先有必要介绍两个基本概念,一个是序列化,一个是反序列化.这两个概念的定义在网上搜一下都很多的,但大多都讲得比较晦涩,不 ...
- google protocol buffer——protobuf的使用特性及编码原理
这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们展示了 ...
- google protocol buffer——protobuf的编码原理二
这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们主要通 ...
- Protobuf使用规范分享
一.Protobuf 的优点 Protobuf 有如 XML,不过它更小.更快.也更简单.它以高效的二进制方式存储,比 XML 小 3 到 10 倍,快 20 到 100 倍.你可以定义自己的数据结构 ...
- protobuf学习(2)-相关学习资料
protobuf官方git地址 protobuf官方英文文档 (你懂的需要FQ) protobuf中文翻译文档 protobuf概述 (官方翻译 推荐阅读) protobuf入门 ...
- Cocos2d-JS/Ajax用Protobuf与NodeJS/Java通信
原文地址:http://www.iclojure.com/blog/articles/2016/04/29/cocos2d-js-ajax-protobuf-nodejs-java Google的Pr ...
- Protobuf C#教程 ThriftC#教程大合辑
android与PC,C#与Java 利用protobuf 进行无障碍通讯[Socket] http://www.cnblogs.com/TerryBlog/archive/2011/04/23/20 ...
随机推荐
- 第五章 使用java实现面向对象异常
第五章 异常 一.异常概述 概述:异常是在程序的运行过程中所发生的不正常的事件,他会中断正在运行的程序 二.异常处理 1.关键字:try catch finally throw throws 2.Tr ...
- DataGridView初始化,加载数据
1,创建winform窗体应用程序 2,在界面上拖入DataGridView控件 3,添加相应的列如图: 4,开始编写后面的代码: private DataTable CountryDt = new ...
- python的爬虫
requests库的安装 https://blog.csdn.net/xiaokuang5020/article/details/80580631 Response对象属性 属性 说明 r.statu ...
- python decode和encode
摘抄: 字符串在Python内部的表示是Unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符解码(decode)成unicode,再从unicode编码 ...
- vim命令“=”、“d”、“y”的用法(结合光标移动命令,一些场合会非常方便)
vim有许多命令,网上搜有一堆贴子.文章列举出各种功能的命令. 对于“=”.“d”.“y”,我在无意中发现了它们所具有的相同的一些用法,先举以下三个例子: =nG dnG ynG 其中,n为行号.注意 ...
- thinkphp的删除操作
1.循环遍历要删除的用户的或者呀删除的文章的id值: <volist name="list" id="vo"> <tr id="si ...
- Ascii码 unicode码 utf-8编码 gbk编码的区别
ASCII码: 只包含英文,数字,特殊符号的编码,一个字符用8位(bit)1字节(byte)表示 Unicode码: 又称万国码,包含全世界所有的文字,符号,一个字符用32位(bit)4字节(byte ...
- 深入理解javascript中的Function.prototye.bind
函数绑定(Function binding)很有可能是你在开始使用JavaScript时最少关注的一点,但是当你意识到你需要一个解决方案来解决如何在另一个函数中保持this上下文的时候,你真正需要的其 ...
- Git Bash Here常用命令以及使用步骤
1.首先,要clone项目代码: git clone 链接地址 2.更新代码: git pull 3.添加修改过的文件.文件夹: git add 修改过的文件,文件夹 4.提交并注释: git com ...
- Linux基础之-Bash命令优先级
一. Bash简介 命令解释器,也就是 Bourne Again Shell,起源于shell.shell俗称壳,它是指UNIX系统下的一个命令解析器:主要用于用户和系统的交互.UNIX系统上有很多种 ...