Protocol buffers-编码

gRCP使用Protocol buffers编写服务定义,使用Protocol buffers定义服务,具体包括定义服务中的远程方法以及希望通过网络发送的消息。那么定义完消息体后,是如何编译成字节流的。
首先,如何使用Protocol buffers定义消息
在这里插入图片描述
数值型的是TV结构
字符类型的是TLV结构

Protocol buffers encoding地址:
https://developers.google.com/protocol-buffers/docs/encoding

回忆一下消息体的定义结构

定义消息体:

message UserInfo {
  optional int32  		id       = 1;
  optional string 		name 	 = 2;
  optional uint32 		age  	 = 3;
  optional Telephone  	tel		 = 4;
  
  message Telephone {
     optional string areacode = 1;
     optional string number   = 2;
  }
}

tag value

通过定义接口可知,我们定义的时候需要定义好类型和字段,其中每个字段都要在Protobuf中,每个字段最后都会被序列化成KV的二进制格式,其中key的格式如下:
tag value = (field_number << 3) | wire_type

tag value:标签,由两个值构成,一个字段索引和路线类型。
field_number:字段索引,.proto文件定义的顺序。
wire_type:路线类型,字段类型,根据不同数值类型映射成不同的编码类型。
wire_type会提供消息来确认值的长度,那么wire_type都有哪些类型。

Protobuf编码类型(wire_type)

在这里插入图片描述

了解了定义字段的字段索引(field_number)和路线类型(wire_type),可以套用刚才的公式来计算咱们标签值(tag value)
在这里插入图片描述

此时标签已经计算好了。现在就要看消息的值了。

编码技术

Protocol buffers使用不同的编码类型来编码不同类型的数据。对于字符型的,通过UTF-8对值进行编码,对于数值型的通常使用Varint的编码技术。那么具体来了解一下常用编码技术

(1)无符号数值类型编码:Varints

Varints(可变长整数)是一种序列化数字的编码方式,使用单字节或多字节来序列化整数的方法,分配的字节数量随值的数字的变化而变化。当一个数字比较小时,占用的字节数就较少,当一个数字较大时,其占用的字节数就较大。
特点:支持变长编码,支持无符号数值
其实现方式是:每个字节的高位不保存数据,只用来标记是否还有下一个字节,剩下的低位字节则用来正常保存数据,存储数字的二进制补码形式。每个字节的最高位称之为the most significant bit(msb)。Protobuffer只是针对常见无符号数字类型的编码采用这种编码格式。
注意:区分大小端的问题,计算机的内部处理都是小端序,Protobuf也采用小端序。所以我们最低有效位是放在MSB前面。
• Big-Endian:大端序,高位字节在前,低位字节在后,这是人类读写数值的方法
• Little-Endian:小端序,低位地址在前,高位地址在后

字段类型:
在这里插入图片描述

举例:
https://tool.oschina.net/hexconvert
在这里插入图片描述

(2)有符号数值编码类型: ZigZag

有符号的整数是能够表示正整数值和负整数值的类型,比如sint32和sint64这样字段类型的。负数的时候就是用zigzag编码转换成正数,然后在使用varint进行编码。

为什么需要通过zigzag类型在使用varint编码?
如果用Varint来编码有符号整数,比如sint64,此时因为原本8个字节需要每个字节都抽出一位填充varint标记,所以全部就需要 64bit / 7bit = 9*7 + 1 = 10bit来表示。这种情况下无疑空间是浪费的。所以对于有符号长整数,protobuf采用ZigZag编码来表示。这样就是为什么sint32和sint64和int32、int64高效的原因。

在zigzag编码中,有符号会将负整数和正整数以"之"字形的方式映射为无符号整数,比如,
在这里插入图片描述

zigzag编码的映射函数为:
ZigZag(n) = (n << 1) ^ (n << k),
k对于sint32,k=31,即用(n << 1) ^ (n >> 31)
k对于sint64来说,k=61,则用(n << 1) ^ (n >> 63)表示。

(3)浮点数值编码类型:non-Varint

非Varint类型与Varint类型相反,是固定数量的字节,字节数与实际值没有关系。

Protocol buffers就两种线路类型属于non-Varint,也就是我们的浮点类型,浮点数的编码格式即为非边长,此时其高位为1或者5
在这里插入图片描述

(4)字符串编码类型: Strings

对于字符串编码来说,属于基于长度分隔(Length-delimited)的类型类型,这意味着首先会有一个经过Varint编码的长度值,随后才是指定数量的字节数据,字符串值会用UTF-8字符编码来进行编码。wireType=2。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值