MikhayEeer's note station
Share some notes during my study and work.
UCAS在读研究生
技术栈:
C/C++/Python/Golang/Linux/Git
对新技术和新事物充满研究激情,欢迎一起交流探讨!
博客有任何问题或建议,欢迎联系我!
by mikhayeeer
CSDN文章链接:https://blog.csdn.net/Topsort/article/details/145955168?fromshare=blogdetail&sharetype=blogdetail&sharerId=145955168&sharerefer=PC&sharesource=Topsort&sharefrom=from_link
struct User {
string name;
int age;
string sex;
};
User u1 = {'Jack', 25, 'Male'};
// 序列化
string str = "Jack\n18\nMale";
当需要将数据存储,保存对象状态;或者网络进行传输数据时,不能传输整个对象;
Socket编程发送与接收就是序列化与反序列化
实现序列化的手段: Protobuf, [[JSON]], [[XML]]
全称 : Protocol Buffers 是Google的 语言无关、平台无关、可扩展的 二进制数据序列化协议 可以用于通信协议、数据存储等场景的 结构化数据 存储传输
proto 比 xml 更小更快更简单 proto 可以定义数据的结构、会自动生成源代码;更新数据结构,不会破坏原有结构编译的已部署程序
编写.proto文件,定义数据结构和属性;
用protoc编译器编译.proto,生成接口;
在目标代码中调用接口;
syntax = "proto3"; // 指定 proto3 语法
package example; // 包名 (命名空间既视感)
message Person {
string name = 1; // 字段类型 + 字段名称 + 唯一编号tag
int32 id = 2;
string email = 3;
repeated string phones = 4;
}
一个字段的完整是:
<规则> <类型> <名> = <编号>;
int32 string bool bytes enum message
optional // 可选
repeated // 重复 数组
oneof // 多选一 [[Protobuf#1.4 oneof 多态]]
1~15只占用1字节
实现复杂结构
message Base {
string base_field = 1;
}
message Derived {
Base base = 1;
string derived_field = 2;
}
可以包含多个类型字段,但是同时只能有一个被设置 多选一需求,不同字段之间是互斥的
message Event {
oneof event_type {
ClickEvent click = 1;
KeyPressEvent keypress = 2;
}
}
message PersonInfo {
string name = 1;
oneof contact {
string qq = 2;
string wx = 3;
}
}
然后在代码中的具体设置
PersonInfo person;
person.set_qq("12987");
person.set_wx("wx_23816"); // 这个时候会 覆盖 qq字段
编写好.proto文件后,利用protoc编译器生成目标语言代码;
protoc --cpp_out=. person.proto
protoc --python_out=. person.proto
protoc --go_out=. person.proto
编译后会生成对应代码
python : persn_pb2.py
go : person.pb.go
c : person.pb.cc 与 person.pb.h
这种还挺常见,例如QT的
.ui会生成ui_xxxx.h
进行序列化
#include "person.pb.h"
// 进行序列化
Person person;
// 构造 赋值
person.set_name( "Jack" );
person.set_id( 65 );
person.set_email( "a@bb.com" );
std::string serialized = person.SerializeToString();
反序列化
Person parsed_person;
parsed_person.ParseFromString( serialized );
set_,has_,clear_
mutable_
add_, _size
person.set_name('Jack');
std::string person_name = person.name();
if ( person.has_email() ) {
// ...
}
person.clear_name();
.proto文件内容
message Address {
string city = 1;
}
message Person{
// ...
Address address = 2;
}
具体使用(C++为例)
Address* addr = person.mutable_address();
addr->set_city("Beijing");
字段定义.proto
message Exam {
// ...
repeated int32 scores = 3;
}
repeated的操作(C++为例)
// 添加
exam.add_scores(90);
exam.add_scores(68);
// 获取
int score_0 = exam.scores(0);
int score_2 = exam.scores(2);
// 修改
exam.mutable_scores(0)->push_back(95);
// size
int size = exam.scores_size();
// 交换 swap
Person p1, p2;
p1.Swap(&p2);
// 合并 merge
p1.MergeFrom(p2);
合并的话,p1字段内容会被p2覆盖或者追加
#proto #xml #json [[JSON]] [[XML]]
| | proto | json | xml |
| —- | ————– | ———————– | ————- |
| 格式 | 二进制 | 文本 键值对 | 文本 标签 |
| 可读性 | 低(需要解析) | 高 | 高(感觉不如json) |
| 传输效率 | 体积小,序列化快 | 体积较大,解析慢 | 体积大,解析慢 |
| 类型支持 | 强类型(预定义) | | |
| 场景 | 高性能通信
大数据传输 | Web API
配置文件
数据交换 | 兼容旧系统
复杂文档 |
message Order {
int64 order_id = 1;
repeated Product products = 2; // 强类型,需要定义 // 数组
float total_price = 3;
Status status = 4; // 强类型,需要定义
enum Status { // 枚举 status
PENDING = 0;
SHIPPED = 1;
DELIVERED = 2;
}
message Product { // 嵌套类型
string name = 1;
int32 quantity = 2;
float price = 3;
}
}
"order" : {
"order_id" : 1,
"products" : [
{"name" : "mouse", "quantity" : 2, "price" : 21.5},
{"name" : "keyboard", "quantity" : 1, "price" : 52.49}
],
"total_price" : 95.49,
"status" : "PENDING"
}
<Order>
<OrderID>1001</OrderID>
<Products>
<Product>
<Name>Laptop</Name>
<Quantity>1</Quantity>
<Price>999.99</Price>
</Product>
<Product>
<Name>Mouse</Name>
<Quantity>2</Quantity>
<Price>25.50</Price>
</Product>
</Products>
<TotalPrice>1050.99</TotalPrice>
<Status>PENDING</Status>
</Order>
.protoprotoc 编译成目标语言HTTP/2, gRPC)gRPC通信: 基于HTTP/2 和 protobuf 的高性能 RPC 框架
常用于 后端之间 的通信
前端(如浏览器),使用JavaScript,就将proto转为js
npm install -g protobufjs
pbjs -t static-module -w commonjs -o data_pb.js data.proto
再进行反序列化 和 序列化操作,传回序列化后的数据到后端
不展示代码
fetch 发送二进制数据