当前位置:   article > 正文

protobuf的安装与基础使用_ubuntu安装protoc3.21.12

ubuntu安装protoc3.21.12

前提

先把之前可能有的删掉

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

安装

  1. 命令安装(版本应该是3.12.4):
sudo apt install protobuf-compiler libprotobuf-dev -y
  • 1
  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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

验证:

protoc --version
whereis protoc
  • 1
  • 2

使用

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; //枚举类型
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行,会在当前目录下生成test.pb.h和test.pb.cc

protoc [-I ./] --cpp_out=. test.proto   若proto里import了proto,可能需要-I指定头文件位置  
  • 1

若是安装在项目目录下:

cd bin/ 
./protoc -I . --cpp_out=. ./*.proto
  • 1
  • 2

后续即可使用,以下为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++) {
		//一层一层往下
	}
}
  • 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

编译:

g++ test.cpp test.pb.cc -I. -lprotobuf
  • 1

运行:

./a.out
  • 1

视频资料:

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;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

程序示例:

#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
  • 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
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

反射机制的好处:
1、定义一个统一的接口处理各种消息类型(本质是因为所有的消息类型都继承message这个父类,所以我们的接口就用message类对象来接收,然后内部获取它的描述descriptor和reflection判断类型,做逻辑处理)。
2、其他应用:动态的构建消息,只要拿到descriptor和reflection,也是可以对他set的。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/1008957
推荐阅读
相关标签
  

闽ICP备14008679号