grpc之protobuf协议的一些实现

Protobuf#

Protocol Buffers是一种轻便高效的结构化数据存储格式,可用于结构化数据串行化,即序列化。适合于做数据存储或RPC数据交换格式。

优点:

  1. 序列化过程快,所需存储的字节数更少。紧凑的数据存储,快速解析
  2. 向后兼容性好。跨语言兼容性好

缺点:

  1. 自解释性不好,因为存储是按二进制来的,不适合来描述数据结构。

为什么要快于XML、JSON等存储格式

因为XML的封解包的过程,需要从文件中读出字符串,再转换为XML文档对象结构模型,之后再从XML文档对象结构模型中读取指定节点的字符串,最后再将这个字符串换成指定类型的变量。这个过程很复杂,需要耗费大量CPU计算来完成词法文法分析。

而Protobuf只需要将一个二进制序列,按照指定格式读取到对应类型即可。

varint编码原理#

编码

对于一个int32的数n,它会重复进行这样一个过程:

  1. 先判断前25位是不是全为0.
  2. 如果是则说明这个数已经要编码完了,直接转为一个字节,退出过程。
  3. 如果不是则说明还要继续编码,取n的后7位,给第8位添1后转为一个字节,然后将n右移7位,继续过程。
解码
  1. 初始化一个数n,令n等于0;
  2. 对于要解码的字节数组进行逆序,因为protobuf是小端存储的。
  3. 然后进行二进制转十进制求和算法,得到最后的数。

优点:

编码原理是基于一个事实,即在一般使用中,绝大部分用到的数都比较小,不至于用32位来存储,会形成很大浪费。因此对于这个数的高位0进行省略。虽然对于那些很大的数会用40位去存储,但在实际应用中,消耗的内存还是大大减少了。

缺点:

由于负数的存储是用的补码,高位是1,会导致varint编码特别大,必定消耗5个字节。因此需要用zigzag来辅助对负数进行编码。

zigzag编码原理#

编码

对于负数n,返回 (n<<1)^(n>>31),然后将返回的数按varint进行编码

实质是将负数的符号位移到了最后一位。

解码

对于字节数组,先按照varint进行解码,获得数n,返回 (n>>>1)^-(n&1)

存储格式T-L-V#

Tag

Tag=(field_number<<3)|wire_type

field_number表示消息中的第几个字段,不允许重复,推荐0~15,会节省字节。

wire_type是0~5,需要3个bit位存储,用于表示不同的数据类型。

Length

对于不同的数据类型,会决定它是否需要Length这个字段。

  • Tag:用varint进行编码
  • Length:用varint编码
  • Value:1.string类型用utf8编码。2.Message是根据内部类型来编码

repeated类型#

repeated类型可看作数组,存储形式是T-L-V。每一个元素都会附加一个相同的Tag,因此有冗余浪费。在末尾加上packed=true字段可以进行压缩,只使用一个Tag。

作者:墨鱼-yyyl

出处:https://www.cnblogs.com/moyu-yyyl/p/18009684

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   墨鱼yyyl  阅读(22)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示