news 2026/4/16 15:46:43

Protobuf快速入门

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Protobuf快速入门

概述:

Protocol Buffers(protobuf)是一种由 Google 提出的语言无关、平台无关的结构化数据描述与序列化机制,通过.proto文件以 IDL 形式定义数据结构,再由编译器自动生成各语言的读写代码;在实际使用中,开发者只需像操作普通对象一样设置字段,protobuf 会将其高效序列化为紧凑的二进制数据用于文件存储或网络传输,相比 JSON/XML 具有体积更小、解析更快、类型约束更严格等优势,常用于高性能服务间通信(如 gRPC)、配置下发和日志/状态同步等场景,是分布式系统和后端工程中的基础通信组件。

例子:

接下来使用一个简单的例子熟悉一下整体的流程和使用:(前提是安装了相关的库,主要是protoc和cmake)

例子就是一个简单的读端和写端交互

首先创建一个工程目录:

proto_demo

|

|

___ |____

| |

| |

proto src

proto:主要是放.proto文件

src:放应用层的程序

(1)在proto目录下创建一个monitor.proto

syntax = "proto3"; //命名空间 package my_monitor; // CPU 采样数据 message CpuSample { uint64 timestamp_ms = 1; // 时间戳(ms) float load_1m = 2; // 1分钟负载 float load_5m = 3; float load_15m = 4; repeated float core_usage = 5; // 每核利用率(数组) } // 一次上报数据 message MonitorReport { string host = 1; // 主机名 CpuSample cpu = 2; // 嵌套 message(组合) map<string, string> tags = 3; // 字典:扩展字段 enum Level { // 枚举:固定取值集合 LEVEL_UNSPECIFIED = 0; // enum 第一个必须是 0(默认值) INFO = 1; WARN = 2; ERROR = 3; } Level level = 4; // 枚举字段 }

数据类型基本和c++的数据类型一样,但是每一个massage里面的字段后面跟着的1,2,3...不是值,是序号,将这个文件进行编译可生成.h .c文件

在proto目录下创建创建cmake文件:

# proto/CMakeLists.txt find_package(Protobuf REQUIRED) set(PROTO_FILES ${CMAKE_CURRENT_SOURCE_DIR}/monitor.proto ) # 生成 .pb.cc / .pb.h 到 build/proto 目录 protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${PROTO_FILES}) add_library(monitor_proto STATIC ${PROTO_SRCS} ${PROTO_HDRS} ) target_include_directories(monitor_proto PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${Protobuf_INCLUDE_DIRS} ) target_link_libraries(monitor_proto PUBLIC ${Protobuf_LIBRARIES} )

(2)在src目录下创建read和write程序,write是将数据进行序列化,read相反对序列化的数据进行反序列化并打印(这两个程序是在本地执行的,所以通过文件流传输就可以,如果通过网络传输就要使用字符流并进行打包进行传输)

write:

#include <fstream> #include <iostream> #include "monitor.pb.h" int main() { // 1) 创建消息对象(相当于一个“结构体实例”) my_monitor::MonitorReport report; // 2) 设置普通字段:string/enum report.set_host("server-01"); report.set_level(my_monitor::MonitorReport::WARN); // 3) 设置嵌套 message:mutable_xxx() 返回可修改指针 auto* cpu = report.mutable_cpu(); cpu->set_timestamp_ms(1730000000000ULL); cpu->set_load_1m(0.42f); cpu->set_load_5m(0.35f); cpu->set_load_15m(0.20f); // 4) repeated 字段:add_xxx() 追加元素 cpu->add_core_usage(0.12f); cpu->add_core_usage(0.55f); // 5) map 字段:mutable_tags() 拿到 map,然后像字典一样写 (*report.mutable_tags())["region"] = "ap-shanghai"; (*report.mutable_tags())["container_id"] = "c123"; // 6) 序列化到二进制文件 std::ofstream ofs("report.bin", std::ios::binary); if (!report.SerializeToOstream(&ofs)) { std::cerr << "Serialize failed\n"; return 1; } std::cout << "Wrote report.bin\n"; return 0; }

read:

#include <fstream> #include <iostream> #include "monitor.pb.h" int main() { my_monitor::MonitorReport report; // 1) 从文件反序列化 std::ifstream ifs("report.bin", std::ios::binary); if (!report.ParseFromIstream(&ifs)) { std::cerr << "Parse failed\n"; return 1; } // 2) 读取普通字段 std::cout << "host=" << report.host() << "\n"; std::cout << "level=" << report.level() << "\n"; // enum 是整数(WARN=2) // 3) 读取嵌套 message if (report.has_cpu()) { // 对 message 字段可以判断是否出现过 const auto& cpu = report.cpu(); std::cout << "load1=" << cpu.load_1m() << "\n"; std::cout << "cores=" << cpu.core_usage_size() << "\n"; for (int i = 0; i < cpu.core_usage_size(); ++i) { std::cout << "core[" << i << "]=" << cpu.core_usage(i) << "\n"; } } // 4) 读取 map if (report.tags().contains("container_id")) { std::cout << "container_id=" << report.tags().at("container_id") << "\n"; } return 0; }

对于里面字段的一些操作都是在编译的时候自动生成的在.h .c文件中,命名规则都是差不多的

🧭 Protobuf C++ API 速查表(proto3)

一、普通字段(string / 数字 / bool / enum)

//proto string host = 1; int32 age = 2; bool ok = 3; enum Level { LEVEL_UNSPECIFIED = 0; INFO = 1; } Level level = 4;
//C++ 用法 // 写 msg.set_host("server-01"); msg.set_age(18); msg.set_ok(true); msg.set_level(MyMsg::INFO); // 读 msg.host(); msg.age(); msg.ok(); msg.level();

二、message 字段(嵌套结构体)

// 改(关键) auto* cpu = msg.mutable_cpu(); cpu->set_load_1m(0.5); // 读 msg.cpu().load_1m(); // 判断是否出现过 msg.has_cpu();

三、repeated 字段(数组 / 列表)

// 写 msg.add_core_usage(0.12); msg.add_core_usage(0.55); // 读 int n = msg.core_usage_size(); for (int i = 0; i < n; ++i) { float v = msg.core_usage(i); }

四、map 字段(键值对)

// 写 (*msg.mutable_tags())["region"] = "ap-shanghai"; // 读 if (msg.tags().contains("region")) { std::string v = msg.tags().at("region"); }

五、has_xxx() 到底什么时候能用?

字段类型

has_xxx()

普通字段(string/int)

❌(proto3 默认无)

message 字段

repeated

map

optional 字段

msg.has_name(); // 可以判断是否真的设置过

六、序列化 / 反序列化(必须会)

//序列化 msg.SerializeToString(&out); msg.SerializeToOstream(&ofs); //反序列化 msg.ParseFromString(in); msg.ParseFromIstream(&ifs);

回到项目:

在src中创建一个cmake对这两个读写程序进行编译

# src/CMakeLists.txt # write 程序 add_executable(write_demo write.cpp ) target_link_libraries(write_demo PRIVATE monitor_proto ) # read 程序 add_executable(read_demo read.cpp ) target_link_libraries(read_demo PRIVATE monitor_proto )

(3)最后构建整个项目的cmake文件,进行整体的构建

#proto_demo/CMakeLists.txt cmake_minimum_required(VERSION 3.10) project(proto_demo CXX) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 先构建 proto 模块 add_subdirectory(proto) # 再构建应用 add_subdirectory(src)

进行构建:

在proto_demo目录下创建一个目录build,并进入进行操作:

cd /proto_demo
mkdir -p build
cd build
cmake ..
make -j8

最后在在build目录会有个src里面有可执行程序

依次执行,可看到现象:

./write_demo
./read_demo

最后讲一下如何安装protobuf

这里使用的是离线安装包的方法

去git上下载这个安装包

执行这个脚本:

#!/usr/bin/env bash set -e cd "$(dirname "${BASH_SOURCE[0]}")" THREAD_NUM=$(nproc) # https://github.com/protocolbuffers/protobuf/releases/download/v3.14.0/protobuf-cpp-3.14.0.tar.gz # Install proto. VERSION="3.14.0" PKG_NAME="protobuf-${VERSION}.tar.gz" tar xzf "${PKG_NAME}" pushd protobuf-${VERSION} mkdir cmake/build && cd cmake/build cmake .. \ -DBUILD_SHARED_LIBS=ON \ -Dprotobuf_BUILD_TESTS=OFF \ -DCMAKE_INSTALL_PREFIX:PATH="/usr/local" \ -DCMAKE_BUILD_TYPE=Release make -j$(nproc) make install ldconfig popd rm -rf PKG_NAME protobuf-${VERSION}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:25:52

Retrieval-Augmented Generation with Conflicting Evidence

突破RAG冲突困境&#xff1a;MADAM-RAG多智能体辩论框架与RAMDocs数据集解析在AI搜索、智能问答等实际场景中&#xff0c;检索增强生成&#xff08;RAG&#xff09;技术早已成为提升大模型事实性的核心方案——它让模型能调用外部知识&#xff0c;避免幻觉和知识过时问题。但现…

作者头像 李华
网站建设 2026/4/16 14:29:42

5步掌握Ultralytics YOLO终极灰度检测方案

5步掌握Ultralytics YOLO终极灰度检测方案 【免费下载链接】ultralytics ultralytics - 提供 YOLOv8 模型&#xff0c;用于目标检测、图像分割、姿态估计和图像分类&#xff0c;适合机器学习和计算机视觉领域的开发者。 项目地址: https://gitcode.com/GitHub_Trending/ul/ul…

作者头像 李华
网站建设 2026/4/16 3:04:14

终极指南:ML Visuals科研绘图神器全解析

终极指南&#xff1a;ML Visuals科研绘图神器全解析 【免费下载链接】ml-visuals &#x1f3a8; ML Visuals contains figures and templates which you can reuse and customize to improve your scientific writing. 项目地址: https://gitcode.com/gh_mirrors/ml/ml-visua…

作者头像 李华
网站建设 2026/4/15 10:32:52

Mitsuba-Blender渲染插件:解决专业渲染痛点的完整方案

还在为Blender内置渲染器的物理精度不足而烦恼吗&#xff1f;Mitsuba-Blender插件为你提供了完美的解决方案。这款强大的集成工具将学术界公认的物理渲染器Mitsuba无缝融入Blender环境&#xff0c;让艺术家和研究人员都能享受到最前沿的渲染技术。&#x1f3af; 【免费下载链接…

作者头像 李华