protocol 协议语言介绍
Protocol Buffer是Google提供的一种数据序列化协议,是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
指定版本
protocol 语言文件后面名为.proto。
文件第一行指定版本。必须在文件首行指定,之前不能有任何空行和注释。可以不指定,默认为proto2。
syntax = "proto3";
定义Message
以message关键字开头,然后指定名称。消息体中时字段的定义,分别指定类型、名称和字段编号。
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
示例中只展示了基础类型字段定义,同样可以指定其他枚举类型或者定义好的Message类型。
在二进制格式中,字段编号与类型标识符结合使用。 1到15范围内的字段编号需要一个字节来编码。 从 16 到 2,047 的数字需要 2 个字节。 所以字段编号 1 到 15 的单字节标识符提供更好的性能,所以应将其用于最基本、最常用的字段。
protocol 基础类型与其他语言类型对应关系 Scalar Value Types
关于字段编号是1到2的29次方减一之间的数。不能使用19000到19999之间的数 (FieldDescriptor::kFirstReservedNumber through FieldDescriptor::kLastReservedNumber))。
复杂类型字段声明
message SearchResponse {
repeated Result results = 1;
}
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
repeated关键字表面该字段是一个重复的值,生成对应语言代码时,会是一个集合字段或属性。
保留字段
如果更新服务的消息删除某些字段,应保证不应重复使用该字段编号。如从现有的message中删除字段应该保留其编号。
message Foo {
reserved 2, 15, 9 to 11; //to表示一个连续的范围值
reserved "foo", "bar";
int32 id = 1;
string name = 3;
}
也可以将reserved 关键字用作未来可能添加字段的占位符。
可以通过编号和名称的方式保留字段,但是不能混合使用
添加注释
protocol 和很多主流语言注释方式相同,使用 // 和 /* ... */的注释方式。
默认值
对于声明的message编码过后,其中定义的字段,会有一个默认的零值。如:
- string:empty
- byte:empty bytes
- bool:false
- numeric type:0
- enum:枚举中定义的第一个值,且必须是0
- For message fields, the field is not set. Its exact value is language-dependent. See the generated code guide for details.
枚举声明
通过enum关键字定义枚举,并什么可以有哪些值。
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
可以看到枚举内的第一个常量定义为0,这是必须的,proto3中所有的字段都是必须的(proto3移除了proto2中required和optional的声明),需要定义一个0的常量作为默认值。
如果枚举不需要共用,可以直接在message内声明并定义,如:
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
Corpus corpus = 4;
}
allow_alias
如果需要一个枚举内不同的变量声明相同的值,需要开启allow_alias 选项。
enum EnumAllowingAlias {
option allow_alias = true;
UNKNOWN = 0;
STARTED = 1;
RUNNING = 1;
}
保留值
enum Foo {
reserved 2, 15, 9 to 11, 40 to max;
reserved "FOO", "BAR";
}
和message定义保留字段一样,不支持序号和名称混合使用。
包(命名空间)声明
通过package关键字指定包名,方便工程化管理,避免命名冲突。对应Go中包名,C#的命名空间。
package foo.bar;
包引入
import引入其他proto文件,对应Go的import,C#的using。
import "google/api/annotations.proto";
proto3 和 proto2 不同版本间定义的message类型可以相互引用,但是proto2 定义的枚举不能被proto3 引入使用。
import public
默认情况下,您只能使用直接导入的 .proto文件定义。然而,有时需要移动 .proto文件到一个新的位置,但不想为此更新所有引用它的.proto文件,此时可以在文件原始位置放置一个仿造的 .proto文件,使用import public将所有导入转发到新位置。任何包含import public语句的proto文件都可以临时依赖import public依赖。例如:
// new.proto
// All definitions are moved here
// old.proto
// This is the proto that all clients are importing.
import public "new.proto";
import "other.proto";
// client.proto
import "old.proto";
// You use definitions from old.proto and new.proto, but not other.proto
编译器通过
-I/--proto_path参数指定搜索导入的文件的目录。如果没有指定,默认会在调用编译器的目录中查找。通常,您应该将--proto_path标志设置为项目的根目录,并对所有导入使用完全限定的名称。
嵌套类型
可以在一个message内部定义一个message,类似C#、java中的内部类
message SearchResponse {
message Result {
string url = 1;
string title = 2;
repeated string snippets = 3;
}
repeated Result results = 1;
}
通过_Parent_._Type_的形式,在外部重复使用定义的嵌套类型
message SomeOtherMessage {
SearchResponse.Result result = 1;
}
更新消息
如果有对现有message跟新的需求,例如在不破坏现有代码的前提下新增字段。应遵循如下规则:
- 不要更改现有字段的编号。
- 如果新增消息字段应提供合理的默认值以保证旧服务的代码与新生成的服务代码之间能正常交互。
- 如果确保一个消息字段不会再使用可以,可以删除。或者重命名字段怎加
OBSOLETE_前缀进行标识,也可以通过预留字段保留字段编号,确保不会重复使用该编号。 - int32, uint32, int64, uint64和bool类型之间时相互兼容的,意味着可以直接修改相应的字段类型而且不破坏兼容性。应该注意的是类似int64改为int32类型是,超出的数据部分会被截断。
- sint32 和sint64 彼此兼容,但与其他整数类型不兼容。
- 如果字节包含消息的编码版本,则嵌入消息与字节兼容。
- 只要字节是有效的UTF-8类型,字符串和字节之间也是是兼容的。
- enum与int32、uint32、int64和uint64协议格式兼容(如果这些值不匹配,它们将被截断)。然而,需要注意的是,当消息被反序列化时,客户端代码可能会以不同的方式对待它们:如,无法识别的proto3枚举类型将保留在消息中,但是当消息被反序列化时,如何表示取决于不同的语言。int字段总是保留其值。
- fixed32与sfixed32兼容, fixed64与sfixed64兼容。
- 单个字段修改为新的oneof成员也是允许的,如果能明确多个字段没有被同时设置,那么多个字段修改为新的onof成员也是相对安全的。任何字段移入现有的oneof成员都是不安全的。
未知字段
未知字段是格式良好的协议缓冲区序列化数据,用于表示解析器无法识别的字段。proto3早期版本中会丢弃未知字段。3.5之后的版本会在解析期间保留未知字段,并包含在序列化输出中以兼容proto2。
Any 类型
Any类型允许将消息作为嵌入类型使用不需要在proto内定义。 类型 Any 可以表示任何已知的 Protobuf 消息类型。使用Any类型需要引入google/protobuf/any.proto包。
import "google/protobuf/any.proto";
message ErrorStatus {
string message = 1;
repeated google.protobuf.Any details = 2;
}
OneOf
如果消息中包含多个字段,但是最多同时只会设置一个值,可以借助Oneof强制约束并节省内存(oneof集中所有的字段共享内存)。
message SampleMessage {
oneof test_oneof {
string name = 4;
SubMessage sub_message = 9;
}
}
设置oneof字段将自动清除oneof字段的其他所有成员。如果设置了几个oneof字段,只有最后一个字段仍然有值。
SampleMessage message;
message.set_name("name");
CHECK(message.has_name());
message.mutable_sub_message(); // Will clear name field.
CHECK(!message.has_name());
oneof集内的字段必须具有唯一的字段编号。oneof中可以添加任何类型的字段但是不能使用repeated字段。但是可以在repeated字段类型内使用oneof关键字。
Maps
map关键字可以很方便的声明一个map类型字段:
//map<key_type, value_type> map_field = N;
map<string, Project> projects = 3;
key_type可以是任何整数或字符串类型(除float和bytes外的任何标量类型)。
声明map时不能和repeated一起使用,可以通过如下方式变相定义一个重复的map
message Order {
message Attributes {
map<string, string> values = 1;
}
repeated Attributes attributes = 1;
}
或者
message MapFieldEntry {
key_type key = 1;
value_type value = 2;
}
repeated MapFieldEntry map_field = N;
服务定义
定义Rpc约束,即声明传入和返回值,可以理解为其他语言中接口(抽象)的定义。
service BlogService {
rpc CreateArticle (CreateArticleRequest) returns (CreateArticleReply) {
option (google.api.http) = {
post: "/v1/article/"
body: "*"
};
}
}
Options
选项(Options)不会影响整体声明,改变的时编译时的处理方式,在google/protobuf/descriptor.proto查看完整支持的options。
Options分为文件级(只能声明在文件最顶级)、消息级(什么在message内)、字段级(声明field)。
选项也可以声明在enum 、service等类型上。官网文档原话Options can also be written on enum types, enum values, oneof fields, service types, and service methods; however, no useful options currently exist for any of these.刚接触还不是很理解后面这段话的含义。
如果有需要自定义选项,参考文档 。
protocol 协议语言介绍的更多相关文章
- SIP (Session Initiation Protocol) 协议
Session Initiation Protocol 介绍 SIP是VoIP技术最常使用的协议,它是一种应用程序层协议,可与其他应用程序层协议配合使用,以控制Internet上的多媒体通信会话. V ...
- Arduino语言介绍
Arduino语言介绍 Arduino语言是建立在C/C++基础上的,其基础是C语言,Arduino语言只不过把AVR单片机(微控制器)相关的一些参数设置都函数化,不用我们去了解他的底层,让不了解AV ...
- DHCP (Dynamic Host Configuration Protocol )协议的探讨与分析
DHCP (Dynamic Host Configuration Protocol )协议的探讨与分析 问题背景 最近在工作中遇到了连接外网的交换机在IPv6地址条件下从运营商自动获取的DNS地址与本 ...
- Objective-C( protocol协议)
protocol 协议 protocol:用来声明方法 1.协议的定义 @protocol 协议名称 <NSObject> // 方法声明列表.... @end 2.如何遵守协议 1> ...
- ISO 基础之 (十三) protocol 协议
一 简绍 protocol,简单来说就是一系列不属于任何类的方法列表,其中声明的方法可以被任何类实现.这种模式一般称为代理(delegation)模式.通过Protocol定义各种行为,在不同的场景采 ...
- R语言实战读书笔记1—语言介绍
第一章 语言介绍 1.1 典型的数据分析步骤 1.2 获取帮助 help.start() help("which") help.search("which") ...
- 【转】iOS开发-Protocol协议及委托代理(Delegate)传值
原文网址:http://www.cnblogs.com/GarveyCalvin/p/4210828.html 前言:因为Object-C是不支持多继承的,所以很多时候都是用Protocol(协议)来 ...
- protocol(协议)
可以用来声明一大堆方法(不能声明成员变量) 只要某个类遵守了这个协议,就相当于拥有这个协议中的所有方法声明 只要父类遵守了某个协议,就相当于子类也遵守了 //定义一个名叫MyProtocol的 ...
- OC语法10——@protocol协议,
参考资料:博客 @protocol,协议: OC中protocol的含义和Java中接口的含义是一样的,它们的作用都是为了定义一组方法规范. 实现此协议的类里的方法,必须按照此协议里定义的方法规范来. ...
随机推荐
- 攻防世界之Web_php_unserialize
题目: <?php class Demo { private $file = 'index.php'; public function __construct($file) { ...
- [VM trunk ports]opensatck VM 单网卡,多VLAN配置
描述 需求产生场景 1.用户在虚机运行 K8S ,采用 VLAN 模式组网,要求 VM 端口要支持 trunk,支持多个 VLAN 网络数据在同一虚拟网卡上传输. 2.需要动态的增删虚拟机上的网络接口 ...
- 【基础篇】js对本地文件增删改查
[基础篇] js对本地文件增删改查--增 js对本地文件增删改查--删 js对本地文件增删改查--改 js对本地文件增删改查--查
- jmeter参数化文件路径问题
问题 win下做好的带参数化文件的脚本,放到linux下运行,由于参数化文件路径不正确,导致脚本运行失败,如果解决这个问题呢? 方案一:参数化路径 比如,参数化文件我放到jmeter的bin目录下,参 ...
- [旧][Android] ButterKnifeProcessor 工作流程分析
备注 原发表于2016.05.21,资料已过时,仅作备份,谨慎参考 前言 在 [Android] ButterKnife 浅析 中,我们了解了 ButterKnife 的用法,比较简单. 本次文章我们 ...
- 报表工具为什么我推荐用Smartbi,数据分析师和初学者都能灵活运用
在很多人入门数据分析师或者投身大数据行业的时候,肯定会接触到报表工具,很多人这时候就会去使用一些Excel插件的报表工具,但是很多报表工具都是需要下载一系列的软件,配置各种复杂的环境.尤其是一些数据分 ...
- 【01】Maven依赖插件之maven-dependency-plugin
一.插件目标(goal) 1.analyze:分析项目依赖,确定哪些是已使用已声明的,哪些是已使用未声明的,哪些是未使用已声明的 2.analyze-dep-mgt:分析项目依赖,列出已解析的依赖项与 ...
- django+vue实现跨域
版本 Django 2.2.3 Python 3.8.8 djangorestframework 3.13.1 django-cors-headers 3.11.0 django实现跨域 说明:此处方 ...
- 【Windows身份认证】NTLM
前言 前几天自己在学习域渗透时突然对Windows的身份认证机制产生了兴趣,但看了好几天自己还是懵懵懂懂,期间自己看了许多师傅的优质文章,也做了一些例子的复现,于是有了这篇文章,可以说是自己的笔记或总 ...
- Scala学习笔记(详细)
第2章 变量 val,var,声明变量必须初始化:变量类型确定后不可更改 数据类型:与java有相同的数据类型,在scala中数据类型都是对象 特殊类型:Unit:表示无值,只有一个实例值写出(),相 ...