protobuf的安装与基础使用

前提

先把之前可能有的删掉

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

安装

  1. 命令安装(版本应该是3.12.4):
sudo apt install protobuf-compiler libprotobuf-dev -y
  1. 源码安装(推荐,因为实际项目对版本可能是有精准要求的)
    https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protobuf-cpp-3.21.12.tar.gz
    下载protobuf-cpp-3.21.12.tar.gz拉到ubuntu,此版本之后的版本都比较难装。安装步骤:
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的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值