protocol buffers使用二进制传输格式传递消息,因此相比于xml,json来说要轻便很多。

示例:假设定义了一个Message

message Test1 {
required int32 a = ;
}

实际使用的时候将a设置为150,然后将其序列化到输出流,查看编码后的message,可以看到如下3个byte

  

解析:

上述三个字节实际分为两部分: 08  96 01。第一部分(08)包含了message成员变量的field number(a=1)和变量类型(Varint),第二部分(96 01)为a的实际值150。

这里面涉及几个概念:

  Varint:这个可以理解为可变长的int类型,数值越小使用的byte越少;

  field number和type:protocol buffer消息为一系列的key-value对。二进制版本的消息使用field number作为key。

当接收到一个message时,解析器可以忽略无法识别的字段,通过这样的方式,也可以在不影响老功能的前提下添加新的字段。 通信格式下的key实际包含2个值:.proto文件中的field number,和通信类型。通信类型如下

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

message流中的key类型为varint,计算方式为:(field_number << 3) | wire_type ,即后三位保存了通信类型

上述第一个字节为08,转化为二进制为0000 1000,没个varint的第一个比特位为MSB位,置位表示后续还有字节。去掉MSB位后为

 

后三位表示类型,值为0,表示类型为Varint;右移三位获取tag值为1(即message中设置的a = 1)

下面获取消息值150,注意:字节顺序为大端序

96 01 = 1001 0110  0000 0001
→ 000 0001 ++ 001 0110 (drop the msb and reverse the groups of 7 bits)
→ 10010110
→ 128 + 16 + 4 + 2 = 150

以上介绍的时varint的编码方式,下面介绍一下其他类型的编码

Signed integer

int32和int64的实际类型都是varint,当它表示负数的时候,为10个固定字节长度的值,效率比较低。可以使用sint32和sint64来表示有符号的数值,它采用ZigZag编码,编码对应关系如下,实际就是把负数从0开始做了扩展。

Signed Original Encoded As
0 0
-1 1
1 2
-2 3
2147483647 4294967294
-2147483648 4294967295

Non-Varint Numbers

非varint的值比较简单,double和fixed64的类型为1,表示64位固定长度的值;类似地,float和fixed32类型为5,表示固定32为长度的值,这两种情况下以小端序存储

Strings

类型为2,假设创建message如下,

message Test2 {
required string b = ;
}

实际消息b=“testing”

  74 65 73 74 69 6e 67

首字节为特殊字节:0001 0010,去除msb位:001 0010,后三位->10表示类型2,右移三位->10表示tag 2;07表示长度为7,74 65 73 74 69 6e 67为"testing"的值。

Embedded Messages

假设定义嵌入的message如下:

message Test3 {
required Test1 c = ;
}

设置Test1.c=150,获得的结果如下,可以看到后三个字节跟上述的一致

1a  08 96 01

Packed Repeated Fields

proto2中使用repeated field需要启用特殊选项[packed=true],在proto3中,默认启用packed。如果packed repeated field中包含0个元素,则它不会出现在被解析的message中。

message Test4 {
repeated int32 d = [packed=true];
}

编码如下:

        // tag (field number 4, wire type 2) ->0010 0,010
// payload size (6 bytes)
// first element (varint 3)
8E // second element (varint 270)
9E A7 // third element (varint 86942)

只有使用了原始数据类型(如32-bit或64-bit的varint)的repeated fields才能称之为"packed"

可以看到string,message,repeated field是有长度字段的,而varint由每个字节的msb位表示一个varint是否有后续字节

proto的类型定义如下:

.proto 说明 C++ Java Python Go Ruby C# PHP
double   double double float float64 Float double float
float   float float float float32 Float float float
int32 使用变长编码,对负数编码效率低,如果你的变量可能是负数,可以使用sint32 int32 int int int32 Fixnum or Bignum (as required) int integer
int64 使用变长编码,对负数编码效率低,如果你的变量可能是负数,可以使用sint64 int64 long int/long int64 Bignum long integer/string
uint32 使用变长编码 uint32 int int/long uint32 Fixnum or Bignum (as required) uint integer
uint64 使用变长编码 uint64 long int/long uint64 Bignum ulong integer/string
sint32 使用变长编码,带符号的int类型,对负数编码比int32高效 int32 int int int32 Fixnum or Bignum (as required) int integer
sint64 使用变长编码,带符号的int类型,对负数编码比int64高效 int64 long int/long int64 Bignum long integer/string
fixed32 4字节编码, 如果变量经常大于228228 的话,会比uint32高效 uint32 int int int32 Fixnum or Bignum (as required) uint integer
fixed64 8字节编码, 如果变量经常大于256256 的话,会比uint64高效 uint64 long int/long uint64 Bignum ulong integer/string
sfixed32 4字节编码 int32 int int int32 Fixnum or Bignum (as required) int integer
sfixed64 8字节编码 int64 long int/long int64 Bignum long integer/string
bool   bool boolean bool bool TrueClass/FalseClass bool boolean
string 必须包含utf-8编码或者7-bit ASCII text string String str/unicode string String (UTF-8) string string
bytes 任意的字节序列 string ByteString str []byte String (ASCII-8BIT) ByteString string

参考:Encoding

protocol buffers的编码原理的更多相关文章

  1. 理解netty对protocol buffers的编码解码

    一,netty+protocol buffers简要说明 Netty是业界最流行的NIO框架之一优点:1)API使用简单,开发门槛低:2)功能强大,预置了多种编解码功能,支持多种主流协议:3)定制能力 ...

  2. Protocol Buffers工作原理

    这里记录一下学习与使用Protocol Buffer的笔记,优点缺点如何使用这里不再叙述,重点关注与理解Protocol Buffers的工作原理,其大概实现. 我们经常使用Protocol Buff ...

  3. Protocol Buffers编码详解,例子,图解

    Protocol Buffers编码详解,例子,图解 本文不是让你掌握protobuf的使用,而是以超级细致的例子的方式分析protobuf的编码设计.通过此文你可以了解protobuf的数据压缩能力 ...

  4. Protocol Buffers(2):编码与解码

    目录 Message Structure 解码代码一窥 varint Protobuf中的整数和浮点数 Length-delimited相关类型 小结 参考 博客:blog.shinelee.me | ...

  5. google protocol buffer——protobuf的使用特性及编码原理

    这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们展示了 ...

  6. google protocol buffer——protobuf的编码原理二

    这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们主要通 ...

  7. 【笔记】直接使用protocol buffers的底层库,对特定场景的PB编解码进行处理,编码性能提升2.4倍,解码性能提升4.8倍

    接上一篇文章:[笔记]golang中使用protocol buffers的底层库直接解码二进制数据 最近计划优化prometheus的remote write协议,因为业务需要,实现了一个remote ...

  8. protocol buffers生成go代码原理

    本文描述了protocol buffers使用.proto文件生成pb.go文件的过程 编译器 编译器需要插件来编译环境,使用如下方式安装插件:go get github.com/golang/pro ...

  9. Google Protocol Buffers介绍

    简要介绍和总结protobuf的一些关键点,从我之前做的ppt里摘录而成,希望能节省protobuf初学者的入门时间.这是一个简单的Demo. Protobuf 简介 Protobuf全称Google ...

随机推荐

  1. (回文串 Manacher )Girls' research -- hdu -- 3294

    http://acm.hdu.edu.cn/showproblem.php?pid=3294 Girls' research Time Limit:1000MS     Memory Limit:32 ...

  2. 解码Base64,并保存图片至本地

    五一去了具有诗情画意的城市---杭州,今天是假期结束后回来上班的第一天,玩饱之后回来,确实精神抖擞了不少; 前段时间开发了有关电子签名的需求,其中有个关于解码Base64图片的知识点,值得关注一下; ...

  3. 我的成长比价系列:java web开发过程中遇到的错误一:sql语句换行错误

    字符串换行导致的错误,确切的说是马虎的错误,自己在编写简单的servlet项目时,在StudentDao.java 中的  查询语句:String  sql= "SELECT Type,fl ...

  4. Linux - 修改文件编码

    enca -L zh_CN -x UTF- file

  5. [JS] IE下ajax请求不生效或者请求结果不更新

    问题描述: IE8及以下版本里用jQuery发简单的GET时,第一次或者新开窗口后的请求没问题,可以正确返回结果.但是之后刷新页面或者触发某些操作得到的ajax请求结果永远和第一次一样. 问题分析: ...

  6. mongodb 命令行安装

    因为下载zip的文件速度快,所以就使用了zip,zip格式的解压完后需要使用命令行安装,步骤大致如下: 1,首先创建一个文件叫mongo的文件,里面包含了数据库存放的目录以及日志,然后在指定的目录下创 ...

  7. vs2017新建.netcore相关项目提示"未检测到任何.NET Core SDK"或打开.net core 相关项目Web层总是未能正常加载

    近来vs2017出现一个非常怪的现象,之前新建.net core相关项目好好的,现在出现问题,如下: 解决办法,是更新vs2017,界面如下:

  8. OI字符串 简单学习笔记

    持续更新qwq KMP 其实是MP啦qwq 就是先自己匹配自己得到状态图,然后再在上面进行模式串的匹配. nxt数组返回的是以该节点结尾的,最长的,在前面出现过的,不相交的,字符串的最靠右的,末位位置 ...

  9. C++ const 和static的总结以及使用

    一  static的使用 (作用域和存储方式) 1.作用域---------->隐藏 静态函数跟静态全局变量的作用类似 (静态函数不能被其它文件所用: 其它文件中可以定义相同名字的函数,不会发生 ...

  10. MySQL(作业练习)

    day59 参考:http://www.cnblogs.com/wupeiqi/p/5748496.html 现有数据库 /* Navicat Premium Data Transfer Source ...