Google Protocol Buffer 使用到了两种编码方式:Varints 和 zigzag。

一 Varints 编码

每个 byte 只用 7bit 表示数字,最高位 bit作为标志位,如果为:

1,表示后续的 byte 也是该数字的一部分;

0,表示结束。

因此值越小的数字使用越少的字节数。例如小于 128 的数只需要用一个 byte 表示。

1: 0000 0001

128: 0111 1111

129: 1000 0001 0111 1111

二 Zigzag 编码

负数最高位(符号位)是1,就相当于一个很大的整数,如果用varints,很浪费空间。

Zigzag 编码用无符号数来表示有符号数字,正数和负数交错,对照表如下:

原始数值 编码后
0 0
-1 1
1 2
-2 3
2 4
-3 5
3 6
... ...

使用 Zigzag 编码后,绝对值小的数字,无论正负都可以采用较少的 byte 来表示,充分利用了 Varints 这种技术。

如果数值有可能为负数,使用 sint 类型,sint 类型数先使用Zigzag编码,再使用 Varints编码。

三 pb的二进制编码设计

先看官方文档中给的 .proto 文件:

package tutorial;

message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3; enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
} message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
} repeated PhoneNumber phone = 4;
} message AddressBook {
repeated Person person = 1;
}

1 Message Buffer

[Field1 | Field2 | ... | Fieldn]

每个Message都是由多个Field的组成。

2 Field

对于简单类型:

Field : [Key | Value]

而集合类型(string, bytes, embedded messages, packed repeated fields)

Field : [Key | Length | content]

Length采用Varints编码,表示content的Bytes数。

3 Key

Key : [tag | type], 其中 tag 占 5bit,type 占 3bit

tag是Message中定义的标记,type是变量的类型。

type最终会被转换成一个枚举类型,即unsigned int类型,对于关系从下面的代码中可以看到:

const FieldDescriptor::CppType
FieldDescriptor::kTypeToCppTypeMap[MAX_TYPE + 1] = {
static_cast<CppType>(0), // 0 is reserved for errors CPPTYPE_DOUBLE, // TYPE_DOUBLE
CPPTYPE_FLOAT, // TYPE_FLOAT
CPPTYPE_INT64, // TYPE_INT64
CPPTYPE_UINT64, // TYPE_UINT64
CPPTYPE_INT32, // TYPE_INT32
CPPTYPE_UINT64, // TYPE_FIXED64
CPPTYPE_UINT32, // TYPE_FIXED32
CPPTYPE_BOOL, // TYPE_BOOL
CPPTYPE_STRING, // TYPE_STRING
CPPTYPE_MESSAGE, // TYPE_GROUP
CPPTYPE_MESSAGE, // TYPE_MESSAGE
CPPTYPE_STRING, // TYPE_BYTES
CPPTYPE_UINT32, // TYPE_UINT32
CPPTYPE_ENUM, // TYPE_ENUM
CPPTYPE_INT32, // TYPE_SFIXED32
CPPTYPE_INT64, // TYPE_SFIXED64
CPPTYPE_INT32, // TYPE_SINT32
CPPTYPE_INT64, // TYPE_SINT64
}; const char * const FieldDescriptor::kTypeToName[MAX_TYPE + 1] = {
"ERROR", // 0 is reserved for errors "double", // TYPE_DOUBLE
"float", // TYPE_FLOAT
"int64", // TYPE_INT64
"uint64", // TYPE_UINT64
"int32", // TYPE_INT32
"fixed64", // TYPE_FIXED64
"fixed32", // TYPE_FIXED32
"bool", // TYPE_BOOL
"string", // TYPE_STRING
"group", // TYPE_GROUP
"message", // TYPE_MESSAGE
"bytes", // TYPE_BYTES
"uint32", // TYPE_UINT32
"enum", // TYPE_ENUM
"sfixed32", // TYPE_SFIXED32
"sfixed64", // TYPE_SFIXED64
"sint32", // TYPE_SINT32
"sint64", // TYPE_SINT64
};

参考:

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

Google Protocol Buffer 的编码方式的更多相关文章

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

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

  2. Google Protocol Buffer的安装与.proto文件的定义

    什么是protocol Buffer呢? Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准. 我理解的就是:它是一种轻便高效的结构 ...

  3. Google Protocol Buffer 的使用和原理

    Google Protocol Buffer 的使用和原理 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式.它 ...

  4. Google Protocol Buffer

    Google Protocol Buffer(protobuf)是一种高效且格式可扩展的编码结构化数据的方法.和JSON不同,protobuf支持混合二进制数据,它还有先进的和可扩展的模式支持.pro ...

  5. 【Google Protocol Buffer】Google Protocol Buffer

    http://www.ibm.com/developerworks/cn/linux/l-cn-gpb/ Google Protocol Buffer 的使用和原理 Protocol Buffers ...

  6. Google Protocol Buffer的安装与.proto文件的定义(转)

    转自(https://www.cnblogs.com/yinheyi/p/6080244.html) 什么是protocol Buffer呢? Google Protocol Buffer( 简称 P ...

  7. 转Google Protocol Buffer 的使用和原理

    Google Protocol Buffer 的使用和原理 Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,很适合做数据存储或 RPC 数据交换格式.它 ...

  8. Google Protocol Buffer 的使用和原理(无论对存储还是数据交换,都是个挺有用的东西,有9张图做说明,十分清楚)

    感觉Google Protocol Buffer无论对存储还是数据交换,都是个挺有用的东西,这里记录下,以后应该用得着.下文转自: http://www.ibm.com/developerworks/ ...

  9. Google Protocol Buffer入门

    简介 Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 ...

随机推荐

  1. Spring整合activiti-modeler5.16遇到的小问题

    接上一篇整合activiti-modeler并成功创建model:Spring整合activiti-modeler5.16   之后,我尝试运用自定义的model部署流程,但是在部署的过程中又遇到了一 ...

  2. 黄聪:WordPress图片插件:Auto Highslide修改版(转)

    一直以来很多人都很喜欢我博客使用的图片插件,因为我用的跟原版是有些不同的,效果比原版的要好,他有白色遮罩层,可以直观的知道上下翻图片和幻灯片放映模式.很多人使用原版之后发现我用的更加帅一些,于是很多人 ...

  3. System.FormatException: Index (zero based) must be greater than or equal to zero and less than the size of the argument list

    static void Main(string[] args) { StringBuilder sb = new StringBuilder(); string test = "124454 ...

  4. Linux 下 MySQL 的彻底卸载和安装配置字符集

    前言: Linux环境下MySQL的安装和配置在网上已经有很多教程了.之所以写这篇文章是因为在配置字符集的时候找了网上的一些教程发现并不能用导致折腾了一阵子.下面的教程均是亲自实践. MySQL的彻底 ...

  5. objective-c中自己创建的对象为什么不能调用release

    dealloc方法,本就不应该手动调用. 你自己创建的对象,看你代码怎么写的了.例子:NSString *str1 = [NSString stringWithString:@"abc&qu ...

  6. PHP $_SERVER['HTTP_REFERER'] 获取前一页面的 URL 地址

    PHP $_SERVER['HTTP_REFERER'] 使用 $_SERVER['HTTP_REFERER'] 将很容易得到链接到当前页面的前一页面的地址.一个例子如下: index.php(实际地 ...

  7. MethodNotAllowedHttpException

    原因:1.没有加表单{{csrf_field()}}:2.除get提交以外,其它提交方式都要csrf_token();3.提交的路由非法,没有定义.

  8. 防止sql注入。xss攻击 方法

    //防止sql注入.xss攻击    /**     * 过滤参数     * @param string $str 接受的参数     * @return string     */    publ ...

  9. Python补充05 字符串格式化 (%操作符)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在许多编程语言中都包含有格式化字符串的功能,比如C和Fortran语言中的格式化输 ...

  10. How to push your code in git

    1. display all the branches git branch -a 2. delete branches git br -d <branch> # 删除某个分支 git b ...