目 录CONTENT

文章目录

Protocol Buffers

TalentQ
2025-06-23 / 0 评论 / 0 点赞 / 34 阅读 / 0 字

protobuf.png

引言

在当今的分布式系统和微服务架构中,数据序列化是一个至关重要的技术环节。无论是服务间通信、数据存储还是网络传输,我们都需要将复杂的数据结构转换为可传输的格式。Protocol Buffers(简称Protobuf)作为Google开发的高性能序列化框架,已经成为业界的标准选择之一。

What's Protocol Buffers?

Protocol Buffers是Google的一种语言无关、平台无关的可扩展机制,用于序列化结构化数据。它类似于XML和JSON,但更小、更快、更简单。通过定义数据结构的模式(schema),Protobuf可以生成多种编程语言的代码,实现高效的数据序列化和反序列化。

1 序列化和反序列化

对象的序列化: 把对象转换为字节序列(字符串)的过程;

对象的反序列化:把字节序列恢复为对象的过程;

主流的序列化和反序列化工具有:XML、JSON、ProtoBuf。

2 什么情况下需要序列化

存储数据:当你想把的内存中的对象状态保存到一个文件中或者存到数据库中时。

网络传输:网络直接传输数据,但是无法直接传输对象,所以要在传输前序列化,传输完成后反序列化成对象。

How do Protocol Buffers Work?

1 定义message

// people_info.proto

syntax="proto3";

package contacts;

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

syntax="proto3";

指定语法版本。推荐使用proto3(默认是proto2),放置当前.proto文件的首行(除注释外的首行)。

package contacts;

声明当前文件的作用域。推荐使用,package 定义的作用域在经过protoc编译器编译后,会变为C++中的命名空间。

message Person { ...

使用 message 关键字定义类。

2 编译成源文件

本文以C++为例。执行protoc --cpp_out=. path/to/people_info.proto ,生成 people_info.pb.h 和 people_info.pb.cc 文件。

编译指令:protoc [--proto_path=IMPORT_PATH] --cpp_out=OUT_DIR PROTO_FILES

protoc:编译工具。

--proto_path:Specify the directory in which to search for imports. May be specified multiple times; directories will be searched in order. If not given, the current working directory is used.

--cpp_out: Generate C++ header and source.

3 在自己项目中使用

/* main.cc */
#include <iomanip>
#include <iostream>
#include <memory>
#include <string>

#include "people_info.pb.h"

std::string stringToHex(const std::string& str) {
  std::stringstream ss;
  for (unsigned char c : str) {
    ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(c)
       << " ";
  }
  return ss.str();
}

int main() {
  GOOGLE_PROTOBUF_VERIFY_VERSION;

  std::string str;
  contacts::Person p;

  p.set_name("talentq");
  p.set_id(1);
  p.set_email("123456@qq.com");
  // serialize
  p.SerializeToString(&str);
  std::cout << "serialize: " << stringToHex(str) << std::endl;

  contacts::Person p2;
  //  deserialize
  p2.ParseFromString(str);
  std::cout << "deserialize: " << p2.name() << " " << p2.id() << " "
            << p2.email() << std::endl;

  google::protobuf::ShutdownProtobufLibrary();

  return 0;
}

GOOGLE_PROTOBUF_VERIFY_VERSION;

验证编译时使用的protobuf头文件版本与运行时链接的protobuf库版本是否匹配,防止因版本不匹配导致的运行时错误。

google::protobuf::ShutdownProtobufLibrary();

清除所有protocol buffer libarary分配的全局对象。

通常情况下这是不需要的,因为程序退出后系统会自动释放内存。在以下情况需要:

  1. 当使用valgrand等内存泄露检查工具,这类工具会要求你显示地释放内存,否则会有内存泄露嫌疑;

  2. 实现一个库文件,这个库文件会被同一个进程加载和卸载多次,这需要在每次卸载时手动释放内存。

SerializeToString() 和 ParseFromString()

Protocol Buffers编译器(protoc)会为每个定义的消息类型自动生成丰富的API方法。上面示例中,SerializeToString()方法将内存中的结构化数据对象转换为紧凑的二进制字节流,这种二进制格式具有跨平台兼容性和高压缩比的特点。相对应地,ParseFromString()方法则负责将二进制数据流还原为可操作的对象实例,实现数据的完整重构。

4 编译&运行

g++ main.cc people_info.pb.cc -o main -l protobuf

./main

适用场景

Protocol Buffers作为一种成熟的序列化技术,在性能、兼容性和易用性方面都表现出色,它特别适合对性能要求高、数据传输频繁的场景,如gRPC通信、消息队列、数据存储等。具体有以下场景:

  • 高性能要求的系统

  • 微服务架构

  • 跨语言数据交换

  • 需要版本演进的长期项目

虽然Protobuf在可读性方面不如JSON和XML,但其在性能和类型安全方面的优势使其成为现代分布式系统的理想选择。随着云原生技术的发展,Protobuf将继续在数据序列化领域发挥重要作用。选择合适的序列化技术需要综合考虑项目需求、团队技能和长期维护成本。对于追求高性能和强类型安全的项目,Protocol Buffers无疑是一个值得考虑的优秀选择。

核心特性

高性能、跨语言支持、向后兼容、强类型系统。

特性

protobuf

JSON

XML

数据格式

二进制格式

文本格式

文本格式

可读性

不可直接阅读

人类可读,结构清晰

人类可读,但较冗长

数据大小

非常紧凑,体积最小

中等大小

最大,标签冗余多

解析速度

最快

较快

最慢

类型安全

强类型,编译时检查

弱类型,运行时检查

弱类型,主要是字符串

向后兼容性

优秀,支持字段添加/删除

一般,需要代码处理

一般,需要谨慎设计

跨语言支持

广泛支持主流语言

几乎所有语言原生支持

广泛支持

网络传输

高效,带宽占用少

中等效率

效率较低

适用场景

微服务、RPC、高性能系统

Web API、配置文件

企业级应用、文档交换

安装编译器 protoc

两种安装方式,推荐使用包管理器安装。

使用包管理器安装:

# for Linux
sudo apt install protobuf-compiler

# for Mac
brew install protobuf

# for Windows
winget install protobuf

直接安装预编译二进制:Release 版本

安装后执行protoc --version ,确保版本是3+。

Reference

ProtoBuf 详解

Google Protocol Buffers简介

https://protobuf.dev/

https://protobuf.dev/overview/

https://protobuf.dev/getting-started/cpptutorial/

https://protobuf.dev/programming-guides/proto3/

0

评论区