Protobuf

欢迎访问我的博客首页


  Protobuf 是 gRPC 的依赖之一,可以直接安装 gRPC

1. 生成源文件


  使用 CMake 编译工具,根据 xxx.proto 生成 xxx.pb.h 和 xxx.pb.cc。整个工程有三个文件,第一个文件是 AddressBook.proto,内容如下。

package tutorial;

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

message AddressBook {
  repeated Person person = 1;
}

  第二个文件是代码文件 main.cpp,内容如下。

#include "AddressBook.pb.h"
#include <fstream>
#include <iostream>
#include <string>
using namespace std;

// 根据用户输入,向地址簿添加一个人的信息。
void PromptForAddress(tutorial::Person *person) {
    cout << "Enter person ID number: ";
    int id;
    cin >> id;
    person->set_id(id);

    cin.ignore(256, '\n');
    cout << "Enter name: ";
    getline(cin, *person->mutable_name());

    cout << "Enter email address (blank for none): ";
    string email;
    getline(cin, email);
    if (!email.empty()) {
        person->set_email(email);
    }

    while (true) {
        cout << "Enter a phone number (or leave blank to finish): ";
        string number;
        getline(cin, number);
        if (number.empty()) {
            break;
        }

        tutorial::Person::PhoneNumber *phone_number = person->add_phone();
        phone_number->set_number(number);

        cout << "Is this a mobile, home, or work phone? ";
        string type;
        getline(cin, type);
        if (type == "mobile") {
            phone_number->set_type(tutorial::Person::MOBILE);
        } else if (type == "home") {
            phone_number->set_type(tutorial::Person::HOME);
        } else if (type == "work") {
            phone_number->set_type(tutorial::Person::WORK);
        } else {
            cout << "Unknown phone type.  Using default." << endl;
        }
    }
}

// Main function:  Reads the entire address book from a file,
//   adds one person based on user input, then writes it back out to the same
//   file.
int main(int argc, char *argv[]) {
    // Verify that the version of the library that we linked against is
    // compatible with the version of the headers we compiled against.
    GOOGLE_PROTOBUF_VERIFY_VERSION;
    if (argc != 2) {
        cerr << "Usage:  " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
        return -1;
    }

    tutorial::AddressBook address_book;
    {
        // Read the existing address book.
        fstream input(argv[1], ios::in | ios::binary);
        if (!input) {
            cout << argv[1] << ": File not found.  Creating a new file." << endl;
        } else if (!address_book.ParseFromIstream(&input)) {
            cerr << "Failed to parse address book." << endl;
            return -1;
        }
    }

    // Add an address.
    PromptForAddress(address_book.add_person());

    {
        // Write the new address book back to disk.
        fstream output(argv[1], ios::out | ios::trunc | ios::binary);
        if (!address_book.SerializeToOstream(&output)) {
            cerr << "Failed to write address book." << endl;
            return -1;
        }
    }

    // Optional:  Delete all global objects allocated by libprotobuf.
    google::protobuf::ShutdownProtobufLibrary();
    return 0;
}

  第三个文件是 CMake 配置文件 CMakeLists.txt,用于根据 xxx.proto 生成 xxx.pb.h 和 xxx.pb.cc,且把代码文件编译成可执行文件。内容如下。

cmake_minimum_required(VERSION 3.2)
project(Protobuf_example)

set(absl_DIR D:/MinGW/libraries/abseil/lib/cmake/absl)
find_package(absl REQUIRED)
set(absl_LIBRARIES
    absl::algorithm
    absl::base
    absl::debugging
    absl::flat_hash_map
    absl::memory
    absl::meta
    absl::numeric
    absl::str_format
    absl::strings
    absl::synchronization
    absl::time
    absl::utility
)

find_package(Protobuf 3.0.0 REQUIRED)
PROTOBUF_GENERATE_CPP(PROTO_HDRS PROTO_SRCS AddressBook.proto)
#message(Protobuf_INCLUDE_DIRS = ${Protobuf_INCLUDE_DIRS})
#message(Protobuf_LIBRARIES = ${Protobuf_LIBRARIES})
#message(PROTO_SRCS = ${PROTO_SRCS})
#message(PROTO_HDRS = ${PROTO_HDRS})

add_executable(${PROJECT_NAME}
	main.cpp
	${PROTO_SRCS}
	${PROTO_HDRS}
)
target_include_directories(${PROJECT_NAME}
    PUBLIC
    ${CMAKE_CURRENT_BINARY_DIR}
    ${PROTOBUF_INCLUDE_DIRS}
)
target_link_libraries(${PROJECT_NAME}
    PUBLIC
    ${PROTOBUF_LIBRARIES}
    ${absl_LIBRARIES}
)

   CMake 使用命令 PROTOBUF_GENERATE_CPP 根据 xxx.proto 生成 xxx.pb.h 和 xxx.pb.cc。这个命令来自位于 Protobuf 安装位置 bin 文件夹中的 protoc.exe,因此要确保该路径在环境变量中。

2. 参考


  1. 例子,51CTO,2021。
  2. 例子,优快云,2020。
### Protocol Buffers 使用指南 Protocol Buffers(简称 Protobuf)是一种语言中立、平台中立、可扩展的序列化结构数据的方式,主要用于通信协议、数据存储等。以下是关于 Protobuf 的相关信息和使用方法。 #### 1. 基本概念 Protobuf 是一种二进制序列化格式,相比 XML 和 JSON 更为紧凑高效[^1]。它通过 `.proto` 文件定义消息结构,并使用 `protoc` 编译器生成多种编程语言的代码。这种方式使得跨平台的数据交换更加简单和高效。 #### 2. 安装与环境配置 要使用 Protobuf,首先需要安装 `protoc` 编译器。可以通过以下命令安装: ```bash # 下载并解压 protoc 二进制文件 wget https://github.com/protocolbuffers/protobuf/releases/download/v3.21.4/protoc-3.21.4-linux-x86_64.zip unzip protoc-3.21.4-linux-x86_64.zip -d protoc3 sudo mv protoc3/bin/* /usr/local/bin/ sudo mv protoc3/include/* /usr/local/include/ ``` 确保 `protoc` 已正确安装后,可以运行以下命令验证版本: ```bash protoc --version ``` #### 3. 定义 `.proto` 文件 `.proto` 文件是 Protobuf 的核心,用于定义消息结构。例如,以下是一个简单的 `.proto` 文件示例: ```proto syntax = "proto3"; // 指定语法版本 package tutorial; message Person { string name = 1; int32 id = 2; string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { string number = 1; PhoneType type = 2; } repeated PhoneNumber phones = 4; } ``` 上述代码定义了一个 `Person` 消息类型,包含姓名、ID、电子邮件和电话号码列表。 #### 4. 生成代码 使用 `protoc` 编译器将 `.proto` 文件转换为目标语言的代码。例如,生成 Python 代码: ```bash protoc --python_out=./ person.proto ``` 这将在当前目录下生成一个 `person_pb2.py` 文件,其中包含 `Person` 消息类型的类定义。 #### 5. 数据序列化与反序列化 以下是一个 Python 示例,展示如何使用生成的代码进行数据的序列化和反序列化: ```python import person_pb2 # 创建一个 Person 对象 person = person_pb2.Person() person.name = "Alice" person.id = 123 person.email = "alice@example.com" # 添加电话号码 phone = person.phones.add() phone.number = "123-456-7890" phone.type = person_pb2.Person.PhoneType.MOBILE # 序列化为字节流 serialized_data = person.SerializeToString() # 反序列化为对象 new_person = person_pb2.Person() new_person.ParseFromString(serialized_data) print(new_person.name) # 输出: Alice ``` #### 6. 文档生成工具 Protobuf 支持使用工具如 `protoc-gen-doc` 自动生成文档,便于维护大型消息定义集。例如,生成 HTML 文档: ```bash protoc --plugin=protoc-gen-doc=path/to/protoc-gen-doc \ --doc_out=./docs \ --doc_opt=html,index.html \ person.proto ``` #### 7. 历史背景 Protobuf 的历史可以追溯到 Google 的内部开发。最初开源时,它实际上是 Google 的第二个语言版本,因此被称为 `proto2`[^2]。目前,Protobuf 提供了两个主要版本:`proto2` 和 `proto3`,后者更简洁且兼容性更强。 #### 8. Python 类型检查支持 对于 Python 开发者,`mypy-protobuf` 插件可以帮助将 Protobuf 消息类型集成到类型注解中,从而增强代码的静态检查能力[^3]。例如: ```python from typing import List import person_pb2 def process_person(person: person_pb2.Person) -> List[str]: return [phone.number for phone in person.phones] ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值