protobuf 中数据编码规则

2023-10-26

背景

protobuf 是一种跨平台的序列化结构数据的方法,可用于网络数据传输及存储;protobuf 在生成的 C++ 代码中为 .proto 文件中的每个 message 生成了对应的 C++ 类,并提供了数据成员的读写方法。

本文对 protobuf 中数据编码规则进行总结,以知其然也知其所以然。

基本概念
①.wire-type

wire-type 指编码类型,如下表所示

wire-type 名称 说明
0 Varint 变长整形
1 64-bits 固定 8 个字节
2 Length-delimited Length+Body 方式
5 32-bits 固定 4 个字节

②.field-number

field-number 即字段的数字标识符,表示字段的唯一性。

③.msb

msb 指每个字节的最高位,Varint 中用来标记后续是否有更多的字节需要读取。

消息结构

①.概述

protobuf 消息的二进制数据是由一系列的键值对依次排列构成:

在这里插入图片描述

其中:Tag 信息:存储 wire-type 和 field-number,用来标识每一个字段;Data 信息:存储字段值编码后的二进制序列。

②.Tag 生成规则

Tag 用一个字节表示,其中低 3 个字节标识 wire-type,生成规则如下:

Tag = field-number << 3 | wire-type

Varint 编码 ①.概述

Varint 编码是一种可变长的编码方式。Varint 每个字节使用低 7 位存储数值,采用小段存储。

②.内存中 int 编码

C++int4 个字节,以整数 200 为例:

std::cout << std::bitset<32>(200) << endl;

在这里插入图片描述

③.protobuf 中 int 编码

示例 message 中定义一个 int32 成员:

message DemoMsg
{
   int32 a = 1;
}

序列化后结果如下:

void printStringByBin(const std::string& s)
{
    for (auto& c : s)
    {
        std::cout << std::bitset<8>(  static_cast<short>(c)) << " ";
    }
    std::cout << std::endl;
}
int main()
{
    protoTest::DemoMsg msg;  
    msg.set_a(200);
    string s = msg.SerializeAsString();
    printStringByBin(s);
}

在这里插入图片描述

整数 200 在经 protobuf 序列化后只需要 2 个字节(仅 Data 部分),Varint 编码中数值越小需要的字节数越少。比如整数 2 只需要 1 个字节:

在这里插入图片描述

④.Varint 编码过程示例

以整数 200 为例 Varint 编码规则如下:

在这里插入图片描述

Length-delimited 编码

①.概述

字符串编码的数据部分由长度和字符序列构成,其中长度采用 Varint 方式编码。string 类型以及 message 、map 等复合类型的字段都是采用 Length-delimited 方式编码,先指定数据长度,然后后面依次是内部各字段的编码。

②.string 编码示例

示例 message 中定义一个 string 成员:

message DemoMsg
{
   string a = 1;
}

序列化后结果如下:

void printStringByHex(const std::string& s)
{
    for (auto& c : s)
    {
        std::cout << std::hex <<std::setfill('0') << std::setw(2) << static_cast<short>(c) << " ";
    }
    std::cout << std::endl;
}

int main()
{
    protoTest::DemoMsg msg;  
    msg.set_a("abcd");
    string s = msg.SerializeAsString();
    printStringByHex(s);
}

在这里插入图片描述

固定长度编码

①.概述

固定长度编码方式 Data 部分采用固定的长度编码,如 fixed32 采用固定 4 个字节表示数字。

②.fixed32 编码示例

示例 message 中定义一个 fixed32 成员:

message DemoMsg
{
   fixed32  a = 1;
}

序列化后结果如下:

int main()
{
    protoTest::DemoMsg msg;  
    msg.set_a(200);
    string s = msg.SerializeAsString();
    printStringByBin(s);
}

在这里插入图片描述

数据类型选择

①.概述

由于不同的编码方式所需要的字节数不一样,为提高数据编码及传输效率,要为 message 中每个字段选择合适的类型。

②.正整数

如果数值是正数,根据值的范围大小使用 uint32 \ uint64 类型,但如果数值总是比较大的话选择 fixed32 \ fixed64。

③.负整数

如果数值可能是负数,根据值的范围大小使用 int32 \ int64 类型;但如果数值总是比较大的话选择 sfixed32 \ sfixed64;

④.浮点数

float \ double 是固定使用 4 \ 8个字节编码,为提高效率可以把浮点数转为整形进行传输;

⑤.字符串

string 和 bytes 都是字符串,但 string 仅支持 UTF-8 或者 7-bit ASCII 编码的文本。

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

protobuf 中数据编码规则 的相关文章

随机推荐

  • 运用决策表设计测试用例

    逻辑关系 逻辑关系 logic relationship 即 依赖关系 在项目管理中 指表示两个活动 前导活动和后续活动 中一个活动的变更将会影响到另一个活动的关系 强制依赖关系 所做工作中固有的依赖关系 可自由处理的依赖关系 由项目队伍确
  • MyBatis:尝试解决Spring Boot集成MyBatis 懒加载时序列化失败的三种方法以及原因FAIL_ON_EMPTY_BEANS

    MyBatis 解决No serializer found for class org apache ibatis executor loader javassist JavassistProxyFactory EnhancedResult
  • python3 Flask 简单入门(MVC模板类)

    跟上一篇文章一样的内容 Flask默认支持的模板是jinja2 jinja2简单实用 1 在Jinja2模板中 我们用 name 表示一个需要替换的变量 很多时候 还需要循环 条件判断等指令语句 在Jinja2中 用 表示指令 2 循环输出
  • win10 装黑苹果 完整教程

    一 材料准备 1 虚拟机软件VMware 2 适用于Windows版本的VMware解锁安装Mac OS的补丁 3 Mac OS X 10 10的黑苹果镜像 以上材料我都为你贴心地准备齐了 在我的云盘获取 链接 https pan baid
  • VUE3+Element-Plus form表单封装

    VUE3 Element Plus form表单封装 新建form组件页面 创建index vue 新建form组件页面 在components中创建新组件 将需要的form表单中常用的UI组件引入 vue3创建组件和vue2中多少有点区别
  • 大学《数据库原理与技术》复习题(二)

    数据库复习题 一 选择题 1 B 是按照一定的数据模型组织的 长期存储在计算机内 可为多个用户共享的数据的集合 A 数据库系统 B 数据库 C 关系数据库 D 数据库管理系统 2 数据库系统的基础是 A 数据结构 B 数据库管理系统 C 操
  • LVGL V8

    本文适用于LVGL V8版本 LVGL simulator vs2019 官方工程 lv sim visual studio 使用注意事项 1 将官方工程从github上下载下来 最好使用git 将整个工程clone下来 因为工程内部有依赖
  • c++坑人

    大家好 我是LCR 今天为大家带来的是c 中的弹窗病毒 当然你也可以把它理解为坑人代码 如果喜欢这篇文章 可以给我点一个赞吗 代码解释 system是c语言库里面自带的一个函数 start的原本意思为 跳转 后面本应接网址 当你的后面为空时
  • 多功能翻译工具:全球翻译、润色和摘要生成

    openai translator openai translator Stars 18 1k License AGPL 3 0 这个项目是一个多功能翻译工具 由 OpenAI 提供支持 可以进行全球单词翻译 单词润色和摘要生成等操作 提供
  • python项目导出依赖包requirements.txt文件

    只导出当前项目依赖包 注意 使用 pip freeze gt requirements txt 会导出大量无用的文件 包括很多个包信息 其实这里是把你当前 python 环境的所有包的相关信息导出来了 如果我们只需导出当前项目所需的依赖包
  • 如何创建线程,多线程下又如何上锁保护公共资源?

    目录 一 创建线程几种方法 1 继承thread类 重写run方法 2 实现runnable接口 重写run方法 3 使用匿名类 或 lamda表达式 让代码更简洁 4 Callable 接口 5 使用线程池创建线程 二 多线程下 需要上锁
  • canvas画布合成

  • windows自动颁发证书

    首先去配置组策略 计算机配置 windows设置 安全设置 公钥策略 证书注册策略和证书服务客户端 不需要勾选禁用用户配置注册策略服务器 用户配置也这样配置 最后进入证书管理器 找到证书模板 右键证书管理 看见一个计算机 去右键 安全这里允
  • 虚拟内存笔记

    虚拟内存 为什么要有虚拟内存 有些进程实际需要的内存很大 超过物理内存的容量 比如一个几十G的游戏 要运行在内存为8G的计算机上 由于多道程序设计 主存是同时可以存放多个进程的逻辑及数据的 这就使得每个进程可用的物理内存更加稀缺 不可能无限
  • [1194]GitLab在web端合并分支

    文章目录 gitlab 在 web 端合并分支 1 1 发起合并操作 1 2 选择源分支和目标分支 1 3 输入合并备注 1 4 合并检查 1 5 完成合并 1 6 查看提交记录 修改的文件及内容 gitlab 在 web 端合并分支 1
  • 概率密度估计(Probability Density Estimation)--Part3:混合模型

    目录 引入 求解方法 MLE法 Clustering E M EM EM算法 大概的说明 较为详细的说明 高斯混合中的
  • 线性代数 --- Gram-Schmidt, 格拉姆-施密特正交化(上)

    Gram Schmidt正交化 在前面的几个最小二乘的文章中 实际上已经看到Gram Schmidt正交化的影子 在我个人看来 Gram Schmidt正交化更像是一种最小二乘的简化算法 下面 我会接着上一篇文章中的最后一个例子讲 慢慢引出
  • 【HDLBits 刷题 10】Circuits(6)Finite State Manchines 10-17

    目录 写在前面 Finite State Manchines Lemmings1 Lemmings2 Lemmings3 Lemmings4 Fsm onehot Fsm ps2 Fsm ps2data Fsm serial 写在前面 HD
  • LeetCode922. 按奇偶排序数组 II

    LeetCode922 按奇偶排序数组 II 给定一个非负整数数组 A A 中一半整数是奇数 一半整数是偶数 对数组进行排序 以便当 A i 为奇数时 i 也是奇数 当 A i 为偶数时 i 也是偶数 你可以返回任何满足上述条件的数组作为答
  • protobuf 中数据编码规则

    背景 protobuf 是一种跨平台的序列化结构数据的方法 可用于网络数据传输及存储 protobuf 在生成的 C 代码中为 proto 文件中的每个 message 生成了对应的 C 类 并提供了数据成员的读写方法 本文对 protob