跳转至

protobuf数据处理

一、简介

Protobuf(Protocol Buffers)是 google 开发的一种数据描述语言,它能够将结构化的数据序列化,并且可以将序列化的数据进行反序列化恢复原有的数据结构。一般用于数据存储以及通信协议方面。

它类似于 JSON,但更小更快,并且可以生成原生语言绑定。您只需定义一次数据结构,然后可以使用特定生成的源代码,轻松地在各种数据流中以及使用各种语言读写结构化数据。

Protobuf 解决了哪些问题?

Protobuf 提供了一种适合用于几兆字节大小的类型化、结构化数据包的序列化格式。该格式适用于瞬时网络流量和长期数据存储。Protobuf 可以扩展新的信息,而不会使现有数据无效,也不需要更新代码。

二、演示功能概述

本教程教你如何用 Air724 开发板,将 table 类型数据转为 Protobuf 格式,还有将 Protobuf 格式转为 table。

三、准备硬件环境

3.1 开发板准备

使用 EVB_Air724 开发板,如下图所示:

淘宝购买链接:Air724UG-NFM 开发板淘宝购买链接

此开发板的详细使用说明参考:Air724UG 产品手册 中的《EVB_Air724UG_AXX 开发板使用说明》,写这篇文章时最新版本的使用说明为:《EVB_Air724UG_A14 开发板使用说明》;开发板使用过程中遇到任何问题,可以直接参考这份使用说明文档。

api:https://doc.openluat.com/wiki/21?wiki_page_id=2068

3.2 数据通信线

USB 数据线一根(micro USB)。

3.3 PC 电脑

WIN7 以及以上版本的 WINDOWS 系统。

3.4 SIM 卡

中国大陆环境下,可以上网的 SIM 卡。一般来说,使用移动,电信,联通的物联网卡或者手机卡都行。

3.5 组装硬件环境

USB 数据线插入 USB 口,另一端与电脑相连,拨码开关全部拨到 ON,串口切换开关选择 UART1,USB 供电的 4V 对应开关拨至 ON 档,SIM 卡放到 SIM 卡槽中锁紧,如下图所示。

四、准备软件环境

4.1 下载调试工具

使用说明参考:Luatools 下载和详细使用

4.2 源码及固件

1.底层 core 下载

下载底层固件,并解压

链接:https://docs.openluat.com/air724ug/luatos/firmware/

如下图所示,红框的是我们要使用到的

2.本教程使用的 demo:

https://gitee.com/openLuat/LuatOS-Air724UG/tree/master/script_LuaTask/demo/protoBuffer2

4.3 下载固件和脚本到开发板中

打开 Luatools,开发板上电开机,如开机成功 Luatools 会打印如下信息。

点击项目管理测试选项。

进入管理界面,如下图所示。

  • 点击选择文件,选择底层固件,我的文件放在 D:\luatOS\Air724 路径中

  • 点击增加脚本或资源文件,选择 之前下载的程序源码,如下图所示。

  • 点击下载底层和脚本,下载完成如下图所示。

五、代码示例介绍

5.1 API 说明

protobuf.load(pbdata)

作用:加载 pb 二进制定义数据。

参数:

参数
传入值类型
解释
pbdata
string
通过 protoc.exe 程序转换得到的数据,通常从文件读取得到

返回值:

返回值类型
解释
bool
成功与否
int
读取了多长

protobuf.encode(tpname, data)

作用:编码 protobuffs 数据包。

参数:

参数
传入值类型
解释
tpname
string
数据类型名称, 定义在 pb 文件中, 由 protobuf.load 加载
data
table
待编码数据, 必须是 table, 内容符合 pb 文件里的定义

返回值:

返回值类型
解释
string
编码后的数据,若失败会返回 nil

protobuf.decode(tpname, data)

作用:解码 protobuffs 数据包。

参数:

参数
传入值类型
解释
tpname
string
数据类型名称, 定义在 pb 文件中, 由 protobuf.load 加载
data
string
待编码数据

返回值:

返回值类型
解释
table
解码后的数据

5.2 protobuf 版本说明

Protocol Buffers(protobuf)有多个版本,主要的版本是 protobuf 2 和 protobuf 3。它们之间存在一些关键的区别,用户在选择时可以根据具体需求进行决定。

5.2.1 主要区别

  • 语法版本:

protobuf 2 使用 syntax = "proto2";

protobuf 3 使用 syntax = "proto3";

  • 字段默认值:

protobuf 2:字段的默认值是根据字段类型决定的,例如 int32 的默认值是 0,string 是 ""。

protobuf 3:所有字段在未设置时都被视为缺失,不再有默认值。对缺失的字段查询会返回 nil。

  • 必需和可选字段:

protobuf 2:支持 required、optional 和 repeated 字段。

protobuf 3:只支持 optional 和 repeated 字段,required 关键字被移除。这是因为在 protobuf 3 中,字段的存在与否通过是否设置来判断。

  • 枚举类型的默认值:

protobuf 2:枚举必须定义一个 0 的默认值。

protobuf 3:可以不强制指定,但通常建议保留 0 作为默认。

  • JSON 支持:

protobuf 3:提供了更好的原生 JSON 支持,允许直接将 protobuf 消息转换为 JSON 格式。

  • 扩展性:

protobuf 2:通过 extend 关键字实现扩展。

protobuf 3:没有扩展功能,但支持使用 Any 类型来封装任意类型的消息。

5.2.2 用户如何选择

选择使用 protobuf 2 还是 protobuf 3 主要取决于以下几个因素:

  • 兼容性:

如果您有现有的系统或库依赖于 protobuf 2,可能需要继续使用 protobuf 2 以确保兼容性。

  • 功能需求:

如果您需要更好的 JSON 支持、更简化的字段处理和不需要强制的字段要求,protobuf 3 是更好的选择。

  • 团队和项目需求:

考虑团队的熟悉程度以及项目的长期维护需求。如果团队已经习惯了 protobuf 2,迁移到 protobuf 3 可能需要额外的学习和适应。

  • 新项目:

对于新项目,通常推荐使用 protobuf 3,因为它是最新的版本,并且在功能和性能上有许多改进。

5.2.3 总结

protobuf 2 和 protobuf 3 各有优缺点,选择哪个版本应根据项目的具体需求、兼容性考虑和团队的熟悉程度来决定。对于新项目,protobuf 3 通常是更好的选择。

5.3 testProtoBuffer.lua 代码

使用 protobuf.encode 序列化,序列化后的二进制数据流以 string 类型赋值给 encodeStr,使用 protobuf.decode 反序列化,反序列化后的数据以 table 类型赋值给 decodeTable,解析数据后打印出来。

addressbook.pb 是一个 Protocol Buffers (protobuf) 描述文件,通常用于定义数据结构和消息格式。这个文件可以用来描述一个地址簿的消息格式,例如联系人信息(名字、电话号码、电子邮件等) 。

addressbook.pb 文件的生成方法参见文档, proto 编译为 pb 方法.txt。

--- 模块功能:proto buffer功能测试.
-- @author openLuat
-- @module protoBuffer.testProtoBuffer1
-- @license MIT
-- @copyright openLuat
-- @release 2018.03.27

module(...,package.seeall)

local protobuf = require"protobuf"
require"utils"

--注册proto描述文件
local pbFile = io.open("/lua/addressbook.pb","rb")
local pbBuf = pbFile:read("*a")
pbFile:close()
protobuf.register(pbBuf)

local addressBook =
{
    name = "Alice",
    id = 12345,
    phone =
    {
        {number = "1301234567"},
        {number = "87654321", type = "WORK"},
        {number = "13912345678", type = "MOBILE"},
    },
    email = "username@domain.com"
}

--protobuf.encode:序列化接口
--protobuf.decode:反序列化接口
sys.taskInit(function()
    sys.wait(8000)
--使用protobuf.encode序列化,序列化后的二进制数据流以string类型赋值给encodeStr
local encodeStr = protobuf.encode("tutorial.Person", addressBook)
log.info("protobuf.encode",encodeStr:toHex())

--使用protobuf.decode反序列化,反序列化后的数据以table类型赋值给decodeTable
decodeTable = protobuf.decode("tutorial.Person", encodeStr)
decodeTable.profile.nick_name = "AHA"
decodeTable.profile.icon = "id:1"
log.info("protobuf.decode",string.format('\tid: %d, name: %s, email: %s', decodeTable.id, decodeTable.name, decodeTable.email))
if decodeTable.profile then
    log.info("protobuf.decode",string.format('\tnick_name: %s, icon: %s', decodeTable.profile.nick_name, decodeTable.profile.icon))
end
for k,v in ipairs(decodeTable.phone) do
    log.info("protobuf.decode",string.format("\tphone NO.%s: %s %s", k, v.number, v.type))
end
end)

5.4 main.lua 代码

本代码为主程序脚本,系统启动后首先会对 4G 网络进行配置,等待网络连接成功,然后加载测试模块。

5.5 protobuf.lua 代码

本代码为 protobuf 底层函数库,感兴趣的朋友可以在文件中查看。

六、开机调试

6.1 开发板开机

连接好硬件并下载固件后,启动 Luatools 软件,系统运行信息将显示在界面中。红框中为开发板连接到 PC 机后正常打印的信息,如下图所示。

6.2 功能调试

使用 protobuf.encode 序列化,序列化后的二进制数据流以 string 类型赋值给 encodeStr,并且打印日志。

使用 protobuf.decode 反序列化,反序列化后的数据以 table 类型赋值给 decodeTable,并且打印日志。

解析 json 数据并且打印日志。

七、常见问题

7.1 打印不了 log 问题

由于这个打印比较靠前,直接打印会丢失打印不出来,可以在 mail.lua 中测试模块之前加一个延时处理 sys.wait(3000)。

给读者的话

本篇文章由杨超开发;

本篇文章描述的内容,如果有错误、细节缺失、细节不清晰或者其他任何问题,总之就是无法解决您遇到的问题;

请登录合宙技术交流论坛,点击文档找错赢奖金-Air724UG-LuatOS-软件指南-通用工具库-protobuf数据处理

用截图标注+文字描述的方式跟帖回复,记录清楚您发现的问题;

我们会迅速核实并且修改文档;

同时也会为您累计找错积分,您还可能赢取月度找错奖金!