跳转至

protobuf数据处理

一、PROTOBUF 介绍

1.1 简介

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

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

PROTOBUF 解决了哪些问题?

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

具体细节可以参考官方文档:https://protobuf.dev/overview/

1.2 proto 编译为 pb 方法

1、根据电脑的操作系统去 https://repo1.maven.org/maven2/com/google/protobuf/protoc/2.6.1/去下载对应的 protobuf2 exe,如果是 windows-x86_64,直接使用本目录下的 protoc-2.6.1-windows-x86_64.exe 即可

2、把 proto 文件复制到本目录

3、打开 cmd,输入 protoc-2.6.1-windows-x86_64 --descriptor_set_out=tracker.pb tracker.proto 命令(注意修改 protoc exe、proto 和 pb 的文件名)就在同一级目录下生成了 proto 对应的 pb 文件

二、演示功能概述

本 demo 通过使用 Air8101 开发板,将 table 类型数据转为 PROTOBUF 格式,以及将 PROTOBUF 格式转为 table。

三、准备硬件环境

“古人云:‘工欲善其事,必先利其器。’在深入介绍本功能示例之前,我们首先需要确保以下硬件环境的准备工作已经完成。”

参考:硬件环境清单,准备以及组装好硬件环境。

四、软件环境

“凡事预则立,不预则废。”在详细阐述本功能示例之前,我们需先精心筹备好以下软件环境。

  1. Luatools 工具
  2. 内核固件文件(底层 core 固件文件):LuatOS-SoC_V10001_Air8101.soc;参考项目使用的内核固件
  3. luatos 需要的脚本和资源文件

脚本和资源文件:https://gitee.com/openLuat/LuatOS-Air8101/tree/master/demo/wlan/softAP

lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;

准备好软件环境之后,接下来查看如何烧录项目文件到 Air8101 开发板,将本篇文章中演示使用的项目文件烧录到 Air8101 开发板中。

五、API 介绍

5.1 protobuf.load(pbdata)

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

参数:

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

返回值:

**返回值类型**
**解释**
bool
成功与否
int
读取了多长, 调试用

5.2 protobuf.encode(tpname, data)

作用:编码 protobuffs 数据包。

参数:

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

返回值:

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

5.3 protobuf.decode(tpname, data)

作用:解码 protobuffs 数据包。

参数:

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

返回值:

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

六、代码示例介绍

6.1 DEMO 主要组件的详细解释:

6.1.1PROJECT 和 VERSION

这两行代码用于设置项目的名称和版本:

PROJECT = "protobuf_demo"
VERSION = "1.0.0"

6.1.2 PB 文件加载

代码检查是否存在文件 /luadb/person.pb,如果存在,就会加载该文件并发布事件 pb_file_exists,这意味着 PROTOBUF 定义文件已成功加载:

local pb_file = "/luadb/person.pb"
if io.exists(pb_file) then
    protobuf.load(io.readFile(pb_file))
    sys.publish("pb_file_exists")
else
    log.info("protobuf","Failed to load file")
end

6.1.3 数据编码

一旦加载了 PROTOBUF 文件,代码会创建一个 Lua 表 tb,并将其编码为 PROTOBUF 数据。之后,它还会使用 JSON 对数据进行编码并打印出来进行对比:

local tb = {
    name = "wendal",
    id = 123,
    email = "abc@qq.com"
}
sys.waitUntil("pb_file_exists")  -- 等待文件加载事件
local pbdata = protobuf.encode("Person", tb)
-- 使用 protobuf 编码
if pbdata then
    log.info("protobuf", "encode", #pbdata, (pbdata:toHex()))  -- 打印编码后的数据长度和十六进制表示
end

local jdata = json.encode(tb)
-- 使用 JSON 编码
if jdata then
    log.info("json", #jdata, jdata)  -- 打印 JSON 编码的数据长度
end

6.1.4 数据解码

解码 PROTOBUF 数据,将编码后的 pbdata 解码成 Lua 表 re,并将其转换为 JSON 格式进行打印:

local re = protobuf.decode("Person", pbdata)  -- 解码数据
if re then
    log.info("protobuf", "decode", json.encode(re))  -- 打印解码后的数据
end

6.2 完整程序清单

注:完整复制后保存为 main.lua,可直接使用

-- main.lua文件
-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "protobuf_demo"
VERSION = "1.0.0"

-- sys库是标配
sys = require("sys")

log.info("main", PROJECT, VERSION)

sys.taskInit(function()

        -- 如果没有这个库, 就云编译一份吧: https://wiki.luatos.com/develop/compile/Cloud_compilation.html
        if not protobuf then
                log.info("protobuf", "this demo need protobuf lib")
                return
        end

        -- 加载 pb 文件, 这个是从pbtxt 转换得到的
        -- 下载资源到模块时不需要下载pbtxt,需要下载person.pb文件
        -- 转换命令: protoc.exe -o person.pb person.pbtxt
        -- protoc.exe 下载地址: https://github.com/protocolbuffers/protobuf/releases
        local pb_file = "/luadb/person.pb"

        if io.exists(pb_file) then
                protobuf.load(io.readFile(pb_file))
                --如果该文件存在,会发布一个事件 pb_file_exists
                sys.publish("pb_file_exists")
        else
                log.info("protobuf","Failed to load file")

        end

        local tb = {
                name = "wendal",
                id = 123,
                email = "abc@qq.com"
        }

        sys.waitUntil("pb_file_exists")

        sys.wait(1000)
        -- 用 protobuf 编码数据
        local pbdata = protobuf.encode("Person", tb)
        if pbdata then
                -- 打印数据长度. 编码后的数据含不可见字符, toHex是方便显示
                log.info("protobuf", "encode",  #pbdata, (pbdata:toHex()))
        end
        -- 用 json 编码数据, 用于对比大小
        local jdata = json.encode(tb)
        if jdata then
                log.info("json", #jdata, jdata)
        end
        -- 可见 protobuffs 比 json 节省很多空间

        -- 后续是演示解码
        local re = protobuf.decode("Person", pbdata)
        if re then
-- 打印数据, 因为table不能直接显示, 这里转成json来显示
log.info("protobuf", "decode", json.encode(re))
        end

end)

-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!

七、功能验证

7.1 下载固件界面

7.2 找不到文件 person.pb 报错日志

7.3 编码为 PROTOBUF 数据并打印出来

7.4 使用 JSON 对数据进行编码并打印出来

7.5 解码 PROTOBUF 数据,并将其转换为 JSON 格式进行打印

总结

至此,我们已使用 Air8101 开发板完成了 如何使用 PROTOBUF 编解码数据。