百色市右江区了建设局网站,麦云短链接,企业网站开发期末报告,手机下载网页上的视频一、protobuf简介#xff1a;
1.1 protobuf的定义#xff1a;
protobuf是用来干嘛的#xff1f;
protobuf是一种用于 对结构数据进行序列化的工具#xff0c;从而实现 数据存储和交换。
#xff08;主要用于网络通信中 收发两端进行消息交互。所谓的“结构数据”是指类…一、protobuf简介
1.1 protobuf的定义
protobuf是用来干嘛的
protobuf是一种用于 对结构数据进行序列化的工具从而实现 数据存储和交换。
主要用于网络通信中 收发两端进行消息交互。所谓的“结构数据”是指类似于struct结构体的数据可用于表示一个网络消息。当结构体中存在函数指针类型时直接对其存储或传输相当于是“浅拷贝”而对其序列化后则是“深拷贝”。
**序列化**将结构数据或者对象转换成能够用于存储和传输的格式。 **反序列化**在其他的计算环境中将序列化后的数据还原为数据结构和对象。
从“序列化”字面上的理解似乎使用C语言中的struct结构体就可以实现序列化的功能将结构数据填充到定义好的结构体中的对应字段即可接收方再对结构体进行解析。
在单机的不同进程间通信时使用struct结构体这种方法实现“序列化”和“反序列化”的功能问题不大但是在网络编程中即面向网络中不同主机间的通信时则不能使用struct结构体原因在于
1跨语言平台例如发送方是用C语言编写的程序接收方是用Java语言编写的程序不同语言的struct结构体定义方式不同不能直接解析
2struct结构体存在内存对齐和 CPU不兼容的问题。
因此在网络编程中实现“序列化”和“反序列化”功能需要使用通用的组件如 Json、XML、protobuf 等。
1.2 protobuf的优缺点
1.2.1 优点
① 性能高效 与XML相比protobuf更小3 ~ 10倍、更快20 ~ 100倍、更为简单。
**② 语言无关、平台无关
**protobuf支持Java、C、Python等多种语言支持多个平台。
**③ 扩展性、兼容性强
**只需要使用protobuf对结构数据进行一次描述即可从各种数据流中读取结构数据更新数据结构时不会破坏原有的程序。
Protobuf与XML、Json的性能对比
测试10万次序列化 测试10万次反序列化 1.2.2 缺点
① 自解释性较差数据存储格式为二进制需要通过 .proto 文件才能了解到内部的数据结构 ② 不适合用来对 基于文本的标记文档如HTML 建模。
1.3 protobuf中的数据类型限定修饰符
protobuf 2 中有三种数据类型限定修饰符
required, optional, repeatedrequired表示字段必选optional表示字段可选repeated表示一个数组类型。
其中 required 和 optional 已在 proto3 弃用了。
1.4 protobuf中常用的数据类型
bool, 布尔类型double, 64位浮点数
float, 32位浮点数int32, 32位整数
int64, 64位整数
uint64, 64位无符号整数
sint32, 32位整数处理负数效率更高
sint64, 64位整数处理负数效率更高string, 只能处理ASCII字符
bytes, 用于处理多字节的语言字符
enum, 枚举类型二、protobuf下载与安装
GitHub 地址 https://github.com/protocolbuffers/protobuf
官方文档地址 https://developers.google.com/protocol-buffers/
Releases 下载地址 https://github.com/protocolbuffers/protobuf/releases
另外往下可以看到分平台的文件 这些是已经 build 好的 Protocol Compiler可以直接下载了用也可以自己下载前面源码文件后自己进行 build
自己下载需要的版本protobuf进行编译成功后会编译出动态库so和protoc编译器这个也可在以上网址进行下载需要的版本
执行protoc编译器成功后会有如下提示
[rootlinux] protoc --version
libprotoc 3.15.8三、protobuf的使用流程
1.1 定义.proto文件
使用protobuf时需要先根据应用需求编写 .proto 文件 定义消息体格式例如
test.proto文件如下
syntax proto3;
package tutorial;option optimize_for LITE_RUNTIME;message Person {int32 id 1;repeated string name 2;
}以–cpp_out上
1、syntax 关键字表示使用的protobuf的版本如不指定则默认使用 “proto2”
2、package关键字 表示“包”生成目标语言文件后对应C中的namespace命名空间用于防止不同的消息类型间的命名冲突
3、message对应C中的类 内部包含各种属性 其中repeated修饰数据类型表示是一个数组的概念
1.2 .proto文件编译
通过protoc编译器把.protoc文件编译出xxxx.pb.cc和xxxxx.pb.h
格式如下
[rootlinux] protoc -I$SRC_DIR --cpp_out$DST_DIR $SRC_DIR/xxx.proto其中 $SRC_DIR表示 .proto文件所在的源目录 –cpp_out$DST_DIR表示生成目标语言C代码的目标目录 xxx.proto表示要对哪个.proto文件进行解析
以上目录最好使用绝对路径
编译出xxx.pb.cc和xxx.pb.h文件后使用的话只需要把文件编译进去并链接protobuf动态库即可
类似这种格式
g main_test.cpp xxx.pb.cc -o main_test -lprotobuf1.3 C使用protobuf实现序列化的示例
在protobuf源码中的 /examples 目录下有官方提供的protobuf使用示例addressbook.proto
参考官方示例实现C使用protobuf进行序列化和反序列化
addressbook.proto :
syntax proto3;
package tutorial;option optimize_for LITE_RUNTIME;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;
}生成的addressbook.pb.h 文件内容摘要
namespace tutorial {class Person;class Person_PhoneNumber;
};class Person_PhoneNumber : public MessageLite {
public:Person_PhoneNumber();virtual ~Person_PhoneNumber();
public://string number 1;void clear_number();const string number() const;void set_number(const string value);//int32 id 2;void clear_id();int32 id() const;void set_id(int32 value);//string email 3; //...
};add_person.cpp :
#include iostream
#include fstream
#include string
#include pbs/addressbook.pb.h
using namespace std;void serialize_process() {cout serialize_process endl;tutorial::Person person;person.set_name(Obama);person.set_id(1234);person.set_email(1234qq.com);tutorial::Person::PhoneNumber *phone1 person.add_phones();phone1-set_number(110);phone1-set_type(tutorial::Person::MOBILE);tutorial::Person::PhoneNumber *phone2 person.add_phones();phone2-set_number(119);phone2-set_type(tutorial::Person::HOME);fstream output(person_file, ios::out | ios::trunc | ios::binary);if( !person.SerializeToOstream(output) ) {cout Fail to SerializeToOstream. endl;}cout person.ByteSizeLong() : person.ByteSizLong() endl;
}void parse_process() {cout parse_process endl;tutorial::Person result;fstream input(person_file, ios::in | ios::binary);if(!result.ParseFromIstream(input)) {cout Fail to ParseFromIstream. endl;}cout result.name() endl;cout result.id() endl;cout result.email() endl;for(int i 0; i result.phones_size(); i) {const tutorial::Person::PhoneNumber person_phone result.phones(i);switch(person_phone.type()) {case tutorial::Person::MOBILE :cout MOBILE phone : ;break;case tutorial::Person::HOME :cout HOME phone : ;break;case tutorial::Person::WORK :cout WORK phone : ;break;default:cout phone type err. endl;}cout person_phone.number() endl;}
}int main(int argc, char *argv[]) {serialize_process();parse_process();google::protobuf::ShutdownProtobufLibrary(); //删除所有已分配的内存Protobuf使用的堆内存return 0;
}输出结果
[serialize_process]
person.ByteSizeLong() : 39
[parse_process]
Obama
1234
1234qq.com
MOBILE phone : 110
HOME phone : 119分析
protobuf提供的序列化和反序列化的API接口函数
class MessageLite {
public://序列化bool SerializeToOstream(ostream* output) const;bool SerializeToArray(void *data, int size) const;bool SerializeToString(string* output) const;//反序列化bool ParseFromIstream(istream* input);bool ParseFromArray(const void* data, int size);bool ParseFromString(const string data);
};三种序列化的方法没有本质上的区别只是序列化后输出的格式不同可以供不同的应用场景使用。 序列化的API函数均为const成员函数因为序列化不会改变类对象的内容 而是将序列化的结果保存到函数入参指定的地址中。
四、拓展 .proto文件中的 option 选项
.proto文件中的option选项用于配置protobuf编译后生成目标语言文件中的代码量可设置为 SPEED CODE_SIZE LITE_RUNTIME 三种。 默认option选项为 SPEED常用的选项为 LITE_RUNTIME。
三者的区别在于
① SPEED默认值 表示生成的代码运行效率高但是由此生成的代码编译后会占用更多的空间。
② CODE_SIZE 与SPEED恰恰相反代码运行效率较低但是由此生成的代码编译后会占用更少的空间通常用于资源有限的平台如Mobile。
③ LITE_RUNTIME 生成的代码执行效率高同时生成代码编译后的所占用的空间也非常少。 这是以牺牲Protobuf提供的反射功能为代价的。 因此我们在C中链接Protobuf库时仅需链接libprotobuf-lite而非protobuf。
SPEED 和 LITE_RUNTIME相比在于调试级别上例如 msg.SerializeToString(str); 在 SPEED 模式下会利用反射机制打印出详细字段和字段值但是 LITE_RUNTIME 则仅仅打印字段值组成的字符串。
因此可以在调试阶段使用 SPEED 模式而上线以后提升性能使用 LITE_RUNTIME 模式优化。
最直观的区别是使用三种不同的 option 选项时编译后产生的 .pb.h 中自定义的类所继承的 protobuf类不同
//1. SPEED模式自定义的类继承自 Message 类
// .proto 文件
option optimize_for SPEED;
// .pb.h 文件
class Person : public ::PROTOBUF_NAMESPACE_ID::Message {};//2. CODE_SIZE模式自定义的类继承自 Message 类
// .proto 文件
option optimize_for CODE_SIZE;
// .pb.h 文件
class Person : public ::PROTOBUF_NAMESPACE_ID::Message {};//3. LITE_RUNTIME模式自定义的类继承自 MessageLite 类
// .proto 文件
option optimize_for LITE_RUNTIME;
// .pb.h 文件
class Person : public ::PROTOBUF_NAMESPACE_ID::MessageLite {};参考
1、https://zhuanlan.zhihu.com/p/594534435?utm_id0