赞
踩
先把之前可能有的删掉
sudo rm -rf /usr/bin/protoc /usr/include/google/ /usr/local/bin/protoc /usr/local/include/google/ /usr/local/lib/libproto* && sudo apt autoremove -y
sudo apt install protobuf-compiler libprotobuf-dev -y
sudo apt update && sudo apt install autoconf automake libtool curl make g++ unzip -y
tar xf protobuf-cpp-3.21.12.tar.gz && rm -f protobuf-cpp-3.21.12.tar.gz && cd protobuf-3.21.12/
./autogen.sh 若有configure就不需要这步了
./configure --prefix=/home/gyl/work/1 --enable-static=no 可以指定安装到哪,不指定就是/usr/local, 自己用一般不指定,工程里作为库依赖最好指定得到include、lib
make install -j$(nproc)
cd .. && rm -rf protobuf-3.21.12/ && sudo ldconfig
验证:
protoc --version
whereis protoc
protobuf会把代码翻译成一个类。
vscode安装vscode-proto3插件,即可语法提示。
创建一个test.proto:常用的基本类型:string, int32,int64,uint32,uint64,enum
syntax = "proto3";
import "xx.proto" //引用其他的proto
package space; //命名空间
message address {
int32 id = 1;
repeated string name = 2; //repeated可重复赋值,表示动态数组;
}
message Msg {
enum Status { //枚举
OK = 0;
ERROR = 1;
}
int32 telephone = 1; //不能只写int
address ad = 2; //就是其他类对象作为本类成员,嵌套
Status status = 3; //枚举类型
}
运行,会在当前目录下生成test.pb.h和test.pb.cc
protoc [-I ./] --cpp_out=. test.proto 若proto里import了proto,可能需要-I指定头文件位置
若是安装在项目目录下:
cd bin/
./protoc -I . --cpp_out=. ./*.proto
后续即可使用,以下为test.cpp
#include <iostream>
#include "test.pb.h"
#include <string>
using namespace std;
int main() {
/* 口诀: 1.看见repeated:就先add申请内存,若能直接赋值,就不要用set
2.看见嵌套类就mutable拿地址;
3.普通的就set */
space::Msg msg; //先创建对象
msg.set_telephone(123456); //注意: set全小写
msg.set_status(OK);
//ad是嵌套类,需要mutable
auto ad = msg.mutable_ad();
ad->set_id(1);
//repeated,就add
for (int i = 0; i < 10; i++) {
ad.add_name("zhang san");
}
string str = "";
if (!SerializeToString(&str)) {
cout << "序列化失败" << endl;
return 1;
}
space::Msg m2;
m2.ParseFromString(str); //string反序列化为对象,赋给msg2
//ParseFromArray(buf, 1024);从数组中反序列化,因为有时候从string反序列化遇到\0就截断了
cout << m2.telephone() << " " << m2.status() << " " << m2.ad().id() << " " << endl;
//遍历数组的就是for循环,如:
auto msg = m2.mutable_msg();
for (int i = 0; i < msg->ad_size(); i++) {
//一层一层往下
}
}
编译:
g++ test.cpp test.pb.cc -I. -lprotobuf
运行:
./a.out
https://www.bilibili.com/video/BV1Ze41197vD?p=6&vd_source=f247ffd7af459a07780fbaa4b5e830d9
protobuf的反射机制:允许运行时动态的处理各种消息类型,常用于处理不确定的类型的情况。
举例说明:假设你要做一个消息处理系统,你会收到各种类型消息,我们可以用反射机制定义一个统一的消息处理接口。
1、所有的消息类型我们要知道,如:
syntax = "proto3";
message Person {
string name = 1;
int32 id = 2;
string email = 3;
}
message Address {
string street = 1;
string city = 2;
int32 zip = 3;
}
程序示例:
#include <iostream>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/message.h>
#include "message.pb.h"
// 动态处理消息的函数
void processMessage(const google::protobuf::Message& message) {
const google::protobuf::Descriptor* descriptor = message.GetDescriptor();
const google::protobuf::Reflection* reflection = message.GetReflection();
std::cout << "Processing message of type: " << descriptor->name() << std::endl;
for (int i = 0; i < descriptor->field_count(); ++i) {
const google::protobuf::FieldDescriptor* field = descriptor->field(i);
std::cout << "Field: " << field->name() << ", ";
switch (field->type()) {
case google::protobuf::FieldDescriptor::TYPE_STRING:
std::cout << "Value: " << reflection->GetString(message, field) << std::endl;
break;
case google::protobuf::FieldDescriptor::TYPE_INT32:
std::cout << "Value: " << reflection->GetInt32(message, field) << std::endl;
break;
// 处理其他字段类型
default:
std::cout << "Unhandled field type" << std::endl;
break;
}
}
}
int main() {
//很多客户端发送了多种消息到服务器
// 创建 Person 消息
Person person;
person.set_name("Alice");
person.set_id(1);
person.set_email("alice@example.com");
// 创建 Address 消息
Address address;
address.set_street("123 Main St");
address.set_city("Anytown");
address.set_zip(12345);
//发送到服务器
//服务器程序:
// 动态处理接收到的消息
processMessage(person);
processMessage(address);
return 0;
}
反射机制的好处:
1、定义一个统一的接口处理各种消息类型(本质是因为所有的消息类型都继承message这个父类,所以我们的接口就用message类对象来接收,然后内部获取它的描述descriptor和reflection判断类型,做逻辑处理)。
2、其他应用:动态的构建消息,只要拿到descriptor和reflection,也是可以对他set的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。