protobuf

protobuf 简介

概念

protobuf 全称 Protocol buffers,是 Google 研发的一种跨语言、跨平台的序列化数据结构的方式,是一个灵活的、高效的用于序列化数据的协议。
特点

在序列化数据时常用的数据格式还有 XML、JSON 等,相比较而言,protobuf 更小、效率更高且使用更为便捷,protobuf 内置编译器,可以将 protobuf 文件编译成 C++、Python、Java、C#、Go 等多种语言对应的代码,然后可以直接被对应语言使用,轻松实现对数据流的读或写操作而不需要再做特殊解析。
Protobuf的优点如下:

1.高效一一序列化后字节占用空间比 XML 少3-10倍,序列化的时间效率比 XML 快 20-100 倍;

2.便捷------可以将结构化数据封装为类,使用方便;

3.跨语言------支持多种编程语言;

4.高兼容性------当数据交互的双方使用同一数据协议,如果一方修改了数据结构,不影响另一方的使

用。
Protobuf 也有缺点:

1.二进制格式易读性差;

2.缺乏自描述。

基本使用流程

在bazel中已经集成了protobuf的编译器,所以直接使用即可。

protobuf的基本使用,需求如下:

创建 protobuf 文件,在该文件中需要生命学生的姓名、年龄、身高、所有的书籍...等信息,然后分别使用C++和Python实现学生数据的读写操作。

实现大致流程如下:

1.编写 proto 文件;

2.配置 BUILD 文件,编译生成对应的 C++ 或 Python 文件;

3.在 C++ 或 Python 中调用。

proto 使用之文件创建

创建 proto 文件

在 /apollo/cyber 目录下新建文件夹 demo_base_proto,文件夹下新建文件 student.proto,并输入如下内容:

cpp 复制代码
//使用的 proto 版本,cyber RT 中目前使用的是 proto2
syntax = "proto2";
//包
package apollo.cyber.demo_base_proto;

//消息 ------message 是关键字,Student 消息名称
message Student {
    //字段
    //字段格式:字段规则,数据类型,字段名称,字段编号
    required string name = 1;
    optional uint64 age = 2;
    optional double height = 3;
    repeated string books = 4;
}

proto 中的字段语法,字段就格式而言主要有四部分组成:字段规则、数据类型、字段名称、字段编号。

1.字段规则

字段类型主要有如下三种:

required------调用时,必须提供该字段的值,否则该消息将被视为"未初始化",不建议使用,当需要把字段修改为其他规则时,会存在兼容性问题。

optional------调用时该字段的值可以设置也可以不设置,不设置时,会根据数据类型生成默认值。repeated ------该规则字段可以以动态数组的方式存储多个数据。

2.数据类型

protobuf 中的数据类型与不同的编程语言存在一定的映射关系,具体可参考官方资料,如下:
官方网站:https://protobuf.dev/programming-guides/proto2/

3.字段名称

变量名

4.字段编号

每个字段都有唯一编号,用于在二进制格式中标识字段。

proto 文件编译

1.编辑 BUILD 文件

在 demo_base_proto 目录下新建 BUILD 文件,并输入以下内容:

cpp 复制代码
load("//tools:python_rules.bzl","py_proto_library")
package(default_visibility = ["//visibility:public"])
proto_library(
    name="student_proto",
    srcs=["student.proto"]
)

cc_proto_library(
    name = "student_cc",
    deps = [":student_proto"],
)

py_proto_library(
    name = "student_py",
    deps = [":student_proto"]
)

代码解释:

1.proto_library 函数

该函数用于生成 proto 文件对应的库,该库被其他编程语言创建依赖库时所依赖。

参数:

name:目标名称

srcs:proto 文件

2.cc_proto_library 函数

该函数用于生成C++相关的proto依赖库

参数:

name:目标名称

deps:依赖的 proto 库名称

3.py_proto_library 函数

该函数用于生成 python 相关的 proto 依赖库

参数:

name:目标名称

deps:依赖的proto 库名称。

注意:

1.使用 py_proto_library 必须声明 load("M/ltools:python_rules.bzl", "py_proto_library");

2.proto_library 函数的参数 name 值必须后缀 _proto 否则,python调用时会抛出异常;

3.为了方便后期使用,建议先添加语句:package(default_visibility = ["//visibility_public"])。

2.编译

终端进入 /apollo 目录,执行编译命令:

bash 复制代码
bazel build cyber/demo_base_proto/...

在 /apollo/bazel-bin/cyber/demo_base_proto 下将生成可以被 C++ 和 python 调用的中间文件。

proto 读写之 C++ 实现

大致步骤如下:

1.编写C++源文件;

2.配置 BUILD 文件;

3.编译;

4.执行。

1.编写 C++ 源文件

cpp 复制代码
/*
    演示C++ 中 protobuf 的基本读写使用
*/
#include "cyber/demo_base_proto/student.pb.h"

using namespace std;


int main(int argc, char const *argv[])
{
    //创建对象
    apollo::cyber::demo_base_proto::Student stu;
    //数据写
    stu.set_name("zhangsan");
    stu.set_age(18);
    stu.set_height(1.75);
    stu.add_books("yuwen");
    stu.add_books("shuxue");
    stu.add_books("english");
    //读数据
    string name=stu.name();
    uint64_t age=stu.age();
    double height=stu.height();

    cout<<"name:"<<name<<"; age:"<<age<<";height:"<<height<<endl;
   for(int i=0;i<stu.books_size();i++){
    string book = stu.books(i);
    cout << book<<"   ";
   } 
   cout<<endl;

    return 0;
}

代码解释:

proto 文件生成的对应的 C++ 源码中,字段的设置与获取有其默认规则:

1.如果是非repeated规则的字段:那么字段值的设置函数对应的格式为: set_xxx(value),获取函数对应的格式为xxx()。

2.如果是repeated规则的字段:那么字段值的设置函数对应的格式为: add_xxx(),获取函数对应的格式为xxx(索引),另外还可以通过函数xxx_size()获取数组中元素的个数。

2.编写BUILD文件

cpp 复制代码
cc_binary(
    name="test_student",
    srcs=["test_student.cc"],
    deps=[":student_cc"]
)

3.编译以及执行

proto 读写之python实现

1.编写 Python源文件;

2.配置 BUILD文件;

3.编译;

4.执行。

1.编写 python 源文件

python 复制代码
#!/usr/bin/env python3

from cyber.demo_base_proto.student_pb2 import Student

if __name__ =="__main__":
    #创建 student对象
    stu = Student()
    # 写数据
    stu.name="automan"
    stu.age=8
    stu.height=1.4
    stu.books.append("class1")
    stu.books.append("class2")
    stu.books.append("class3")
    # 读数据
    print("name  =  %s, age = %d, height = %.2f" %(stu.name,stu.age,stu.height))

for book in stu.books:
    print("book = %s" %book)

2.编辑 BUILD

cpp 复制代码
py_binary(
    name="test_student_py",
    srcs=["test_student_py.py"],
    deps=[":student_py"]
)

3.编译和执行

。。。

相关推荐
通信仿真实验室21 分钟前
(10)MATLAB莱斯(Rician)衰落信道仿真1
开发语言·matlab
勿语&24 分钟前
Element-UI Plus 暗黑主题切换及自定义主题色
开发语言·javascript·ui
吾爱星辰4 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
ChinaDragonDreamer4 小时前
Kotlin:2.0.20 的新特性
android·开发语言·kotlin
IT良4 小时前
c#增删改查 (数据操作的基础)
开发语言·c#
Kalika0-05 小时前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
_.Switch5 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
代码雕刻家5 小时前
课设实验-数据结构-单链表-文教文化用品品牌
c语言·开发语言·数据结构
一个闪现必杀技5 小时前
Python入门--函数
开发语言·python·青少年编程·pycharm
Fan_web5 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery