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. Linux下编译java并生成jar包

    下面是WordCount.java类 package com.ll; import java.io.IOException; import java.util.Iterator; import jav ...

  2. bzoj4165: 矩阵

    Description 定义和谐矩阵为长不小于 Mina 且宽不小于 Minb 的矩阵,矩阵的权值为整个矩阵内所有数的和.给定一个长为 N ,宽为 M 的矩阵 A,求它的所有和谐子矩阵中权值第 K 小 ...

  3. golang获取字符串长度需要注意的地方

    中文长度,直接贴代码 package main import ( "fmt" "unicode/utf8" ) func main() { aa := &quo ...

  4. html中select标签获取选中value和text

    $("#id").find("option:selected").text(); //获取Select选择的Text$("#id").val ...

  5. sealed修饰符

    sealed(C# 参考) 当对一个类应用 sealed 修饰符时,此修饰符会阻止其他类从该类继承. 在下面的示例中,类 B 从类 A 继承,但是任何类都不能从类 B 继承. class A {} s ...

  6. 黄聪:发送键盘指令System.Windows.Forms.SendKeys.Send

    若要指定在按键(如 Enter 或 Tab)时不显示的字符,以及表示操作而不表示字符的键,请使用下表中的代码:   键 代码 Backspace {BACKSPACE}.{BS} 或 {BKSP} B ...

  7. Flash AS 响应双击事件MouseEvent.DOUBLE_CLICK

    没想到在WinForm简简单单的一个问题,在AS里会成为一个坑. 我遇到的这个问题是由于Loader没有设置doubleClickEnabled=true而导致的. 因此出现这个问题,请思考是否由于此 ...

  8. CE_现金账户转账汇入汇出交易(案例)(未完成)

    2014-07-15 BaoXinjian 一.摘要 二.案例   通过 Oracle Payments 结算事务处理 通过付款模板 事物处理子类型 已验证 -> 正在结算中 ->

  9. NeHe OpenGL教程 第十八课:二次几何体

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  10. android js调试

    http://blog.allenm.me/ 其他平台去这篇文章看 //js调试调试功能支持4.4版本以上的 if(Build.VERSION.SDK_INT >= Build.VERSION_ ...