热门标签 | 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官网

推荐阅读
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • This article discusses the efficiency of using char str[] and char *str and whether there is any reason to prefer one over the other. It explains the difference between the two and provides an example to illustrate their usage. ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • Google在I/O开发者大会详细介绍Android N系统的更新和安全性提升
    Google在2016年的I/O开发者大会上详细介绍了Android N系统的更新和安全性提升。Android N系统在安全方面支持无缝升级更新和修补漏洞,引入了基于文件的数据加密系统和移动版本的Chrome浏览器可以识别恶意网站等新的安全机制。在性能方面,Android N内置了先进的图形处理系统Vulkan,加入了JIT编译器以提高安装效率和减少应用程序的占用空间。此外,Android N还具有自动关闭长时间未使用的后台应用程序来释放系统资源的机制。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
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社区 版权所有