热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入探索protobuf协议学习笔记

目录简介官方API解读(C)定义一个ProtocolFormat编译ProtocolBuffersTheProtocolBufferAPI解析和序列化官方示例注释总结你知道的越多&

目录

    • 简介
    • 官方API解读(C++)
      • 定义一个Protocol Format
      • 编译Protocol Buffers
      • The Protocol Buffer API
      • 解析和序列化
    • 官方示例注释
    • 总结


你知道的越多,你知道的越少。


简介

什么是protobuf?

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等
在网络通信和通用数据交换等应用场景中经常使用的技术是 JSONXML
Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。
你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序

其具有以下特点:

  • 语言无关、平台无关。即 ProtoBuf 支持 JavaC++Python 等多种语言,支持多个平台
  • 高效。即比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单
  • 扩展性、兼容性好。你可以更新数据结构,而不影响和破坏原有的旧程序

官网:protobuf官网

官方示例:官方示例下载

GitHub源码:protobuf-GitHub

官方API解读(C++)

大致步骤:

  • 定义一个.proto文件
  • 使用protocol buffer编译器
  • 使用c++ API读写这个文件

定义一个Protocol Format

定义一个Protocol模板

message Example1 {optional string stringVal = 1;optional bytes bytesVal = 2;message EmbeddedMessage {int32 int32Val = 1;string stringVal = 2;}optional EmbeddedMessage embeddedExample1 = 3;repeated int32 repeatedInt32Val = 4;repeated string repeatedStringVal = 5;
}

message 关键字后跟上消息名称

message xxx {// do something
}

之后我们在其中定义了 message 具有的字段,形式为:

message xxx {// 字段规则:required -> 字段只能也必须出现 1 次// 字段规则:optional -> 字段可出现 0 次或1次// 字段规则:repeated -> 字段可出现任意多次(包括 0)// 类型:int32、int64、sint32、sint64、string、32-bit ....// 字段编号:0 ~ 536870911(除去 1900019999 之间的数字)字段规则 类型 名称 = 字段编号;
}

关于保留字requiredoptionalrepeated可见

  • required:必须为该字段提供一个值,否则该消息将被视为“未初始化”
  • optional:该字段可能被设置,也可能没有设置
  • repeated:该字段可以重复任何次数(包括零)

更多介绍可见官网

编译Protocol Buffers

我们在 .proto 文件中定义了数据结构,这些数据结构是面向开发者和业务程序的,并不面向存储和传输

当需要把这些数据进行存储或传输时,就需要将这些结构数据进行序列化、反序列化以及读写。那么如何实现呢?不用担心, ProtoBuf将会为我们提供相应的接口代码。如何提供?答案就是通过 protoc 这个编译器

编译器下载地址:protoc编译器下载

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto

他最后会生成两个文件

  • addressbook.pb.h:声明生成的类的头文件
  • addressbook.pb.cc:其中包含您的类的实现

The Protocol Buffer API

对于一个message,protoc都会生成一个struct(class),而struct中的属性字段,都会自动的生成一些访问器

/* 是否存在这个属性 */inline bool has_name() const;/* 清除这个属性 */inline void clear_name();/* 获取引用 */inline const ::std::string& name() const;/* 设置这个属性的值,只有字段是string才会有 */inline void set_name(const ::std::string& value);/* 设置这个属性的值 */inline void set_name(const char* value);/* 获取一个指针,只有字段是string才会有 */inline ::std::string* mutable_name();

类中的方法本身是隐式的内联函数inline

而对于一些可重复的字段repeated,会生成以下字段

/* 这个message的数量 */inline int phones_size() const;/* 清除这个message */inline void clear_phones();/* 正常取值 */inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phones() const;/* 获取一个指针 */inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phones();/* 根据索引获取指定的字段 */inline const ::tutorial::Person_PhoneNumber& phones(int index) const;/* 根据索引更新指定的字段的指针 */inline ::tutorial::Person_PhoneNumber* mutable_phones(int index);/* 在可重复essage中添加一个新的值*/inline ::tutorial::Person_PhoneNumber* add_phones();

更详细可见C&#43;&#43; generated code reference

还有一些标准接口

每个消息类还包含许多其他方法&#xff0c;让你检查或操作整个消息&#xff0c;包括:

  • bool IsInitialized() const;&#xff1a; 检查是否设置了所有必需的字段。
  • string DebugString() const;&#xff1a;返回人类可读的消息表示形式&#xff0c;对调试特别有用。
  • void CopyFrom(const Person& from);&#xff1a;使用给定消息的值覆盖消息。
  • void Clear();&#xff1a;将所有元素清除回空状态

解析和序列化

最后&#xff0c;每个协议缓冲区类都有使用协议缓冲区二进制格式编写和读取所选类型的消息的方法。这些包括&#xff1a;

  • bool SerializeToString(string* output) const;&#xff1a;对消息进行序列化并将字节存储在给定字符串中。注意&#xff0c;字节是二进制的&#xff0c;不是文本;我们只将string类用作方便的容器。
  • bool ParseFromString(const string& data);&#xff1a;解析来自给定字符串的消息
  • bool SerializeToOstream(ostream* output) const;&#xff1a;将消息写入给定的c&#43;&#43; ostream。
  • bool ParseFromIstream(istream* input);&#xff1a;从给定的c&#43;&#43; istream中获取消息。

官方示例注释

#include
#include
#include
#include "addressbook.pb.h"
using namespace std;// 该函数根据用户输入填充Person消息
void PromptForAddress(tutorial::Person* person) {// do something
}int main(int argc, char* argv[]) {//验证我们所链接的库的版本//与我们编译的头文件版本兼容。GOOGLE_PROTOBUF_VERIFY_VERSION;// 对AddressBook进行一个实例化tutorial::AddressBook 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;}}PromptForAddress(address_book.add_people());{// 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;}}// 可选:删除libprotobuf分配的所有全局对象。google::protobuf::ShutdownProtobufLibrary();return 0;
}

总结


  • XMLJSONProtoBuf都具有数据结构化和数据序列化的能力
  • XMLJSON 更注重数据结构化&#xff0c;关注人类可读性和语义表达能力。ProtoBuf 更注重数据序列化&#xff0c;关注效率、空间、速度&#xff0c;人类可读性差&#xff0c;语义表达能力不足&#xff08;为保证极致的效率&#xff0c;会舍弃一部分元信息&#xff09;
  • ProtoBuf 的应用场景更为明确&#xff0c;XMLJSON 的应用场景更为丰富

只能说&#xff0c;各有所长&#xff0c;各有所短吧。

参考&#xff1a;

  1. 深入 ProtoBuf - 简介
  2. protobuf官网

推荐阅读
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 数据库内核开发入门 | 搭建研发环境的初步指南
    本课程将带你从零开始,逐步掌握数据库内核开发的基础知识和实践技能,重点介绍如何搭建OceanBase的开发环境。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 在当前众多持久层框架中,MyBatis(前身为iBatis)凭借其轻量级、易用性和对SQL的直接支持,成为许多开发者的首选。本文将详细探讨MyBatis的核心概念、设计理念及其优势。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 本教程涵盖OpenGL基础操作及直线光栅化技术,包括点的绘制、简单图形绘制、直线绘制以及DDA和中点画线算法。通过逐步实践,帮助读者掌握OpenGL的基本使用方法。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.xmlbeans.SchemaType 类的 getBaseEnumType() 方法,提供了多个代码示例,并解释了其在不同场景下的使用方法。 ... [详细]
  • ###问题删除目录时遇到错误提示:rm:cannotremoveusrlocaltmp’:Directorynotempty即使用rm-rf,还是会出现 ... [详细]
  • 本文详细介绍了Java中的输入输出(IO)流,包括其基本概念、分类及应用。IO流是用于在程序和外部资源之间传输数据的一套API。根据数据流动的方向,可以分为输入流(从外部流向程序)和输出流(从程序流向外部)。此外,还涵盖了字节流和字符流的区别及其具体实现。 ... [详细]
author-avatar
mobiledu2502931467
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有