Protocol Buffer (二)原理篇

上一篇文章简单地描述了一下Protocol Buffer的用法,懂得了上篇文章的用法之后,相信大家正常使用Protocol Buffer已经没有太大问题了,没有覆盖到的细节用法,在网上搜一下应该也不难找到。然而知其表而复知其理,知其华而复知其实,所以今天这篇文章给大家介绍一下Protocol Buffer的一些编码原理,可以用来解释为什么序列化之后的数据包比XML和JSON小那么多。

一、Varint编码
Protocol Buffer 在对数字进行编码使用的是Varint的编码方式。我们使用的int类型,一般需要占用4个字节的长度,采用Varint编码,可以用一个字节或多个字节来表示一个数字,值越小的数字占用越少的字节数。

Varint的每个byte的最高位bit用来表示后续的byte是不是也属于该数字的一部分。如果最高位为0,则表示该byte是这个数字的最后一个byte,如果最高位为1,表示后面的一个byte仍然是该数字的一部分。以无符号数为例,对于0-127,只需要一个字节表示,最高位为0,后7位表示值。如果一个数字需要多个字节去表示,这里面有个需要注意的地方:高位的数字是放在后面的字节里面的。

example:300的Varint编码为1010 1100,0000 0010,去掉两个最高位为010 1100,000 0010,将后面的字节放到前面为000 0010 010 1100,也就是100101100,换算成十进制就是300了。

对于有符号的数字,Protocol Buffer 还会采用ZigZag编码,这样无论正数还是负数,绝对值小的时候使用Varint编码占用的字节数就会更少。ZigZag编码大家从下面一张图就可以看明白原理了。

ZigZag编码.png

二、消息体编码
我们平时用JSON传递数据,Java对象序列化为JSON串之后一般会是下面这个样子。

{"code":200,"name":"magiccoder","sex":"man","index":"www.magiccoder.net"}

可能平时一直这么用,大家都已经习以为常了,但是这个对象的数据包在频繁传输的过程中,key值其实是一直重复传输的,key值仅仅是一个标志位,只要客户端和服务端约定之后采用同样的key值就可以,如果把key值直接约定为从1开始的自然数,肯定是比上面的JSON串的长度要短的。甚至我们可以这么想,把需要传输的字段值按照约定的顺序排列下来,做好字段之间的分界,就连key值都不需要了。

Protocol Buffer使用的是Tag-Length-value的形式来组织数据的,Length字段非必需。

  • Tag值有两个作用,一是标志该字段在message中是第几个值,二是标明该字段的数据类型。按照官方文档的说法,他们用Tag中的3个bit来表示数据类型。这样对于固定长度的数据字段,在反序列的时候,通过数据类型的长度就可以正确地界定和取出数据。对于Varint类型的字段,程序也可以按照Varint的编码方式将value值计算出来。下面这张图片是从官方截取的,大家可以看到一共有5种数据类型,那么就需要3个二进制去表示。Tag值采用Varints编码,如果Tag占用一个字节,1个bit用来表示MSB,3个bit用来表示数据类型,还有4个bit用来表示字段在message中的位置,最多可以表示16个字段,一般可以满足大部分需要了。


    wiretype.png
  • length字段表示可变长度的字段时用到的,属于可选字段。对于上图中type序号为2的类型,字段长度不是固定的,像大家熟知的String类型,长度变化范围太大,单靠数据类型已经没法界定它的范围了。Protocol Buffer 使用的策略是在Tag值之后用一个length字段来标志value的长度,这样也就可以正确的界定字段的范围啦。

  • 对于repeated字段和optional字段,如果没有设置,序列化的时候就会被直接忽略,不会参与消息体编码。

三、Protocol Buffer 的其他优点
笔者认为Protocol Buffer除了数据包小,序列化和反序列化速度快,还有下面两个很不错的优点:

  • 语言互通
    现在很多编程语言都已经支持Protocol Buffer 了,到笔者写这篇文章的时候,Java、C++、C#、python、Golang都已经支持了。像我们之前做通讯软件的时候一样,后端使用Golang,客户端使用Java,两边直接使用同一份proto文件描述的message,就可以自动生成通信用的类或者结构体,可以减少非常多的麻烦。客户端跟后端闹得不愉快,大部分时候都是因为通信的消息体出问题。
  • 向后兼容
    软件发布新版本的时候,经常会出现这样的情况,旧版的软件跟新的软件在通信协议方面不兼容。如果使用Protocol Buffer的话,新通信协议中添加的新字段不会影响到旧版本的软件,它会把自己不具有的字段忽略掉。

附上官方网站,上面介绍的还是很全面的,英文还不错的同学可以看一下:
https://developers.google.com/protocol-buffers/

2017年第一周,最近玩的太high了,所以过了这么久才更新这篇文章。
最后祝大家2017年身体健康、工作顺利、心想事成、笑口常开~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,373评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,732评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,163评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,700评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,036评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,425评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,737评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,421评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,141评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,398评论 2 243
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,908评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,276评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,907评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,018评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,772评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,448评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,325评论 2 261

推荐阅读更多精彩内容