博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
序列化和反序列化及Protobuf 基本使用
阅读量:5249 次
发布时间:2019-06-14

本文共 2811 字,大约阅读时间需要 9 分钟。

序列化和反序列化

序列化和反序列化在平常工作中会大量使用,然而并不一定非常清楚它的概念。序列化和反序列化的选型却是系统设计或重构一个重要的环节,在分布式、大数据量系统设计里面更为显著。机器间的通信需要约定一个协议,序列化和反序列化时这个通信协议的一部分。

序列化:将对象或数据结构转为字节序列的过程。
反序列化:将序列化后生成的字节序列转为对象或数据结构的过程。

常用序列化和反序列化组件

比较常见的序列化和反序列化组方式有XML、JSON和Protobuf等。XML标准化较早,基于XML的SOAP是一种应用广泛的结构化数据传递协议。JSON源于js,较之XML它更小、解析更快,而且同样具备可读性好的优点。而源于谷歌的protobuf现在在大型分布式系统广泛使用。

Protobuf

Protobuf是谷歌旗下的一款平台无关,语言无关,可扩展的序列化和反序列化技术。

字段规则

要使用Protobuf,首先需要定义.proto文件

如下proto2中:

message msg{    required int32 a=1;    optional string b=2;    repeated string c=3;}

其中:

  • message是消息定义的关键字。
  • required 表示这个字段必须的,必须在序列化的时候被赋值。
  • optional 代表这个字段是可选的,可以为0个或1个但不能大于1个。
  • repeated 则代表此字段可以被重复任意多次包括0次。类似C++ STL中的vector。
  • int32和string是字段的类型。后面是我们定义的字段名。
  • 最后的1,2,3则是代表每个字段的一个唯一的编号标签,在同一个消息里不可以重复。这些编号标签用与在消息二进制格式中标识你的字段,并且消息一旦定义就不能更改。需要说明的是标签在1到15范围的采用一个字节进行编码。所以通常将标签1到15用于频繁发生的消息字段。编号标签大小的范围是1到\(2^{29}-1\)。此外不能使用protobuf系统预留的编号标签(19000 -19999)。

而在proto3中,字段规则中去除了required和optional,增加singular。但是proto3仍兼容proto2

message msg{    int32 a=1;    singular string b=2;    repeated string c=3;}

其中,

  • singular:一个格式良好的消息应该有0个或者1个这种字段(但是不能超过1个)。
  • repeated
  • 在proto3中,repeated的标量域默认情况下使用packed。

一个较完整的.proto文件

syntax = "proto3";message Article {  int32 article_id = 1;  singular string article_excerpt = 2;  repeated string article_picture = 3;  singular int32  article_pagecount = 4 [default = 0];  enum ArticleType {    NOVEL = 0;    PROSE = 1;    PAPER = 2;    POETRY = 3;  }  singular ArticleType article_type = 5 [default = NOVEL];  message Author {    string name = 1;     singular string phone = 2;  }  singular Author author = 6;  repeated int32 article_numberofwords = 7 [packed=true];  reserved  9, 10, 12 to 15;  extensions 100 to 1000;}extend Article {  singular int32 followers_count = 101;  singular int32 likes_count= 102;}message Other {  singular string other_info = 1;  oneof test_oneof {    string code1 = 2;    string code2 = 3;  }}
  • 上面proto文件,我们定义了enum枚举类型,嵌套的消息。甚至对原有的消息进行了扩展,也可以对字段设置默认值。添加注释等,类似C++注释。
  • 此外reserved关键字主要用于保留相关编号标签,主要是防止在更新proto文件删除了某些字段,而未来的使用者定义新的字段时重新使用了该编号标签。这会引起一些问题在获取老版本的消息时,譬如数据冲突,隐藏的一些bug等。所以一定要用reserved标记这些编号标签以保证不会被使用。
  • 当我们需要对消息进行扩展的时候,我们可以用extensions关键字来定义一些编号标签供第三方扩展。这样的好处是不需要修改原来的消息格式。就像上面proto文件,我们用extend关键字来扩展。只要扩展的字段编号标签在extensions定义的范围里。
  • 对于基本数值类型,由于历史原因,不能被protobuf更有效的encode。所以在新的代码中使用packed=true可以更加有效率的encode。注意packed只能用于repeated 数值类型的字段。不能用于string类型的字段。
  • 在消息Other中我们看到定义了一个oneof关键字。这个关键字作用比较有意思。当你设置了oneof里某个成员值时,它会自动清除掉oneof里的其他成员,也就是说同一时刻oneof里只有一个成员有效。这常用于你有许多optional字段时但同一时刻只能使用其中一个,就可以用oneof来加强这种效果。但需要注意的是oneof里的字段不能用singular,repeated关键字。

导入定义

我们总不能都定义在一个文件中。当一个proto文件需要另一个proto文件的时候,我们可以通过import导入。protobuf也提供了包的定义,只要在文件开头定义package关键字即可。

import "test.proto"package foo.bar;

编译问题

针对不同语言,依据.proto文件编译成我们需要的语言文件。如C++下

protoc -I=SRC_DIR --cpp_out=DST_DIR SRC_DIR/ex.proto

先简单记录这些。

转载于:https://www.cnblogs.com/dengchj/p/7453432.html

你可能感兴趣的文章
Leetcode 92. Reverse Linked List II
查看>>
windown快速安装xgboost
查看>>
Linux上安装Libssh2
查看>>
九.python面向对象(双下方法内置方法)
查看>>
go:channel(未完)
查看>>
[JS]递归对象或数组
查看>>
LeetCode(17) - Letter Combinations of a Phone Number
查看>>
Linux查找命令对比(find、locate、whereis、which、type、grep)
查看>>
路由器外接硬盘做nas可行吗?
查看>>
python:从迭代器,到生成器,再到协程的示例代码
查看>>
Java多线程系列——原子类的实现(CAS算法)
查看>>
在Ubuntu下配置Apache多域名服务器
查看>>
多线程《三》进程与线程的区别
查看>>
linux sed命令
查看>>
LeetCode 160. Intersection of Two Linked Lists
查看>>
html标签的嵌套规则
查看>>
[Source] Machine Learning Gathering/Surveys
查看>>
HTML <select> 标签
查看>>
类加载机制
查看>>
tju 1782. The jackpot
查看>>