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. LinearLayout属性baselineAligned的作用及baseline

    相信大家对LinearLayout已经相当熟悉,但你们是否了解它的属性baselineAligned呢? Android官方文档是这么描述的:

  2. thinkphp在为图片添加png水印不足的处理

    thinkphp在为图片加水印的时候.如果水印图片是png图片,透明度处理很不理想,与是做以下处理 在Image.class.php中新增 static function imagecopymerge ...

  3. Add LUN to ASM in Linux

    # Create new LUN for Linux in the AMS2100 # echo "- - -" >/sys/class/scsi_host/host3/sc ...

  4. ubuntu ipv6网络电视(avplay)

    首先在ubuntu下安装好ipv6 (话说是已经装好了的,不过最好检查以下) 网上有很多资源,我不写了. 测试一下 :ping ipv6.scau.edu.cn 另外,关于ipv6 网络播放器很多人推 ...

  5. 2014 年10个最佳的PHP图像操作库

    2014 年10个最佳的PHP图像操作库   Thomas Boutell 以及众多的开发者创造了以GD图形库闻名的一个图形软件库,用于动态的图形计算. GD提供了对于诸如C, Perl, Pytho ...

  6. PUA

    约会技巧 kino技巧 被拒绝的应对方法 (1)一般约会7个小时后,就能带女生回家 (2)点菜时多点一点,以回家放菜为名 (3)理由要文雅 (4)开酒店的理由 第一时间触碰测试 (1)第一次约会要第一 ...

  7. scala高级内容(二) - Implicit

    一. Implicit关键字 隐士转换 (1)隐士转换函数:用implicit修饰的,只有一个参数的函数.他会被自动执行,来把一个值转换成另一个 class RichFile(val f:File){ ...

  8. ServletContext(重要)

    一个项目只有一个ServletContext对象! 我们可以在N多个Servlet中来获取这个唯一的对象,使用它可以给多个Servlet传递数据! 这个对象在Tomcat启动时就创建,在Tomcat关 ...

  9. Windows服务程序和安装程序制作

    转:http://www.cr173.com/html/15350_1.html 本文介绍了如何用C#创建.安装.启动.监控.卸载简单的Windows Service 的内容步骤和注意事项. 一.创建 ...

  10. 图片_ _ Bitmap_Drawable_Image?

    ===== 2 ==== 1 b.读取res/drawable目录下的 png或者bmp Resources r = this.getContext().getResources(); //以数据流的 ...