protobuf学习记录
安装
1 2
| sudo apt-update sudo apt install -y protobuf-compiler protobuf-c-compiler
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| syntax = "proto2";
package protoTest;
message Example1 {
optional string name = 1;
optional int32 age = 2;
message EmbeddedMessage {
optional string stringVal = 1;
optional bytes bytesVal = 2;
}
}
|
1、syntax 关键字表示使用的protobuf的版本,如不指定则默认使用
“proto2”
2、package关键字
表示“包”,生成目标语言文件后对应C++中的namespace命名空间,用于防止不同的消息类型间的命名冲突
3、message对应C++中的类, 内部包含各种属性,
其中repeated修饰数据类型表示是一个数组的概念
编译
1
| protoc [-I] --xxx_out=OUT_DIR file.proto
|
如 1
| protoc --cpp_out=. example.proto
|
1
| g++ main_test.cpp xxx.pb.cc -o main_test -lprotobuf
|
这样会报错 必须链接pthread(为什么)参考
1
| g++ main.cpp example.pb.cc -o main_test -lprotobuf -pthread
|
需要注意的是,message的同级属性的num不能重复 1
| 编号也是有范围的,编号只能从`1 ~ 2^29 -1`之间进行取数,其中`19000 ~ 19999`不可取,因为这些编号已经被PB官方征用了!使用了编译就会出错;
|
参考1
在C++中引用
package定义的命名空间会转换为C++中的namespase命名空间,message定义的类会转换为C++中国class定义的类,同时还会增加一系列与该属性字段相关的方法:
- clear_xxx(): 清除改字段的值;
- xxx(): 获取当前字段的值;
- set_xxx(): 为当前字段设置值;
- mutable_xxx()
:获取当前字段的地址,对于自定义类型来说protoc不会为其生成set_xxx()的方法来设置值,因为它没办法预测用户到底想如何给自定义类型设置值,但是它会生成对应的mutable_xxx()函数,利用mutable_xxx()函数我们可以获取到当前字段的地址,然后再利用字段的内置set_xxx()方法进行对自定义类型中的各个字段进行初始化,对于protobuf内置的类型protoc不会为其生成mutable_xxx()方法,当然string等除外,这些基本类型利用set_xxx()方法就能够设置值了。
序列化与反序列化
![20240715100645.png] ![20240715100654.png]
项目实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| syntax = "proto2";
package rina.planning;
message TrafficLightState {
enum TLState {
INIT = 0;
LANE_FOLLOW = 1;
APPROACH = 2;
STOP = 3;
UNKNOWN_LIGHT = 4;
CROSSING = 5;
TURN_WAIT = 6;
}
optional TLState tl_state = 1;
}
|
交通灯信号,定义枚举变量TLState和一个TLState字段tl_state。
看上去项目中的protobuf主要的数据类型是double,bool和enum
在其中添加了一个tl_id的字段,然后测试一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #include <iostream>
#include <string>
#include <fstream>
#include "example.pb.h"
int main()
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
rina::planning::TrafficLightState state;
state.set_tl_state(rina::planning::TrafficLightState_TLState_APPROACH);
state.set_tl_id(1);
std::string str;
state.SerializeToString(&str);
std::cout << "序列化结果: " << str << std::endl;
rina::planning::TrafficLightState state2;
state2.ParseFromString(str);
std::cout << "反序列化结果: " << "state: " << state2.tl_state() << "id: " << state2.tl_id()<< std::endl;
return 0;
}
|