GRPC入门和基础知识

GRPC是google开源的一个高性能、跨语言的RPC框架,基于HTTP2协议,基于protobuf 3.x,基于Netty 4.x +。
GRPC使用protobuf序列化协议,基于protobuf来声明数据模型和RPC接口服务。

RPC流程图

 

1、服务调用方(Client)将远程方法的信息(如类名、方法方法名、方法传入的参数)封装为统一的请求体;
2、序列化请求对象,转化为二进制串,方便传输;
3、通过 Client Stub 发送消息到指定的服务提供方;
4、Server Stub 接收来自 Client 的消息;
5、反序列化二进制串,转化为对象,方便使用;
6、根据请求体,执行本地方法;
7、封装方法执行结果为统一的响应体;
8、序列化响应体对象,转化为二进制串;
9、通过 Server Stub 将消息发送给对应的 Client;
10、Client Stub 接受消息;
11、反序列化二进制串,转化为对象;
12、得到方法执行的结果。

基本数据类型

proto TypeJava TypeDefault Value
doubledouble0
floatfloat0
int32int0
uint32int0
uint64long0
sint32int0
sint64long0
fixed32int0
fixed64long0
sfixed32int0
sfixed64long0
boolbooleanfalse
stringString空string
bytesByteString空的bytes

枚举

枚举类型必须将其第一个类型映射为0且零值必须为第一个元素。
枚举常量必须在32位整型值的范围内,因为enum值是使用可变编码方式的,对负数不够高效,因此不推荐在enum中使用负数。

一个数值可以对应多个枚举值,必须标明option allow_alias = true; 

enum EnumAllowingAlias {
  option allow_alias = true;
  UNKNOWN = 0;
  STARTED = 1;
  RUNNING = 1;
}

时间戳

import public "google/protobuf/timestamp.proto";
google.protobuf.Timestamp regists_time = 1;//注册时间

日期

com.google.type.Date opening_date=1;

Any

Any类型允许包装任意的message类型:

import "google/protobuf/any.proto";

message Response {
    google.protobuf.Any data = 1;
}

可以通过pack()unpack()(方法名在不同的语言中可能不同)方法装箱/拆箱,以下是Java的例子:

People people = People.newBuilder().setName("proto").setAge(1).build();
// protoc编译后生成的message类
Response r = Response.newBuilder().setData(Any.pack(people)).build();
// 使用Response包装people

System.out.println(r.getData().getTypeUrl());
// type.googleapis.com/example.protobuf.people.People
System.out.println(r.getData().unpack(People.class).getName());
// proto

Any对包装的类型会生成一个URL,默认是type.googleapis.com/packagename.messagename(在Java中可以通过这个特性进行反射操作)。

Oneof

如果你有一些字段同时最多只有一个能被设置,可以使用oneof关键字来实现,任何一个字段被设置,其它字段会自动被清空(被设为默认值):

message SampleMessage {
  oneof test_oneof {
    string name = 4;
    SubMessage sub_message = 9;
  }
}

 oneof块中的字段不支持repeated

Maps

pb中也可以使用map类型(官方并不认为是一种类型,此处称之为类型仅便于理解),绝大多数scalar类型都可以作为key,除了浮点型和bytes,枚举型也不能作为key,value可以是除了map以外的任意类型:

// map<key_type, value_type> map_field = N;
map<string, Project> projects = 3;

 map类型字段不支持repeated,value的顺序是不定的。

map其实是一种语法糖,它等价于以下形式:

message MapFieldEntry {
  key_type key = 1;
  value_type value = 2;
}

repeated MapFieldEntry map_field = N;

选项

选项不对message的定义产生任何的效果,只会在一些特定的场景中起到作用,下面是一部分例子,完整的选项列表可以前往google/protobuf/descriptor.proto查看(Java语言可以在jar包中找到):

  1. option java_package = "com.example.foo"; 编译器为以此作为生成的Java类的包名,如果没有该选项,则会以pb的package作为包名。
  2. option java_multiple_files = true; 该选项为true时,生成的Java类将是包级别的,否则会在一个包装类中。
  3. option optimize_for = CODE_SIZE; 该选项会对生成的类产生影响,作用是根据指定的选项对代码进行不同方面的优化。
  4. int32 old_field = 6 [deprecated=true]; 把字段标为过时的。

 

 

Protobuf文件

指定正在使用的语法

指定正在使用proto3语法,如果你没有指定这个,编译器会使用proto2。这个指定语法行必须是文件的非空非注释的第一个行。

syntax = "proto3";

选项

Java_package

表明生成java类所在的包,如果在.proto文件中没有明确的声明java_package,就采用默认的包名。当然了,默认方式产生的 java包名并不是最好的方式,按照应用名称倒序方式进行排序的。如果不需要产生java代码,则该选项将不起任何作用。

option java_package = "com.example.foo";

java_outer_classname

表明想要生成Java类的名称。如果在.proto文件中没有明确的java_outer_classname定义,生成的class名称将会根据.proto文件的名称采用驼峰式的命名方式进行生成。如(foo_bar.proto生成的java类名为FooBar.java),如果不生成java代码,则该选项不起任何作用。

option java_outer_classname = "Yuanda"

objc_class_prefix

设置Objective-C类的前缀,添加到所有Objective-C从此.proto文件产生的类和枚举类型。没有默认值,所使用的前缀应该是苹果推荐的3-5个大写字符,注意2个字节的前缀是苹果所保留的。

option objc_class_prefix = "Grpc";

deprecated

如果设置为true则表示该字段已经被废弃,并且不应该在新的代码中使用。

int32 old_field = 6 [deprecated=true];

定义包名

包名应以公司名称开头,以及主要版本。

package com.yuanda.paas.v1.course;

导入定义

如果想要使用的已经在其他.proto文件中已经定义过的消息类型通过import方式进行导入。

import "myproject/other.proto";

默认情况下只能使用直接导入的.proto文件中的定义。 然而, import public 依赖性会通过任意导入包含import public声明的proto文件传递。

import public "google/protobuf/timestamp.proto";

定义消息类型

指定字段类型

所有字段都是必须制定数据类型,可以是基本数据类型也可以是其他的合成类型,如枚举或其他消息类型。

分配标识符

在消息定义中,每个字段都有唯一的一个数字标识符。这些标识符是用来在消息的二进制格式中识别各个字段的,一旦开始使用就不能够再改变。[1,15]之内的标识号在编码的时候会占用一个字节,[16,2047]之内的标识号则占用2个字节,所以应该为那些频繁出现的消息元素保留 [1,15]之内的标识号。切记:要为将来有可能添加的、频繁出现的标识号预留一些标识号。
最小的标识号可以从1开始,最大到2^29 - 1, or 536,870,911。不可以使用其中的[19000-19999], Protobuf协议实现中对这些进行了预留。

指定字段规则

repeated
在一个格式良好的消息中,这种字段可以重复任意多次(包括0次)。重复的值的顺序会被保留。
在proto3中,repeated的标量域默认情况虾使用packed。

注释

在.proto文件中使用//添加注释。

定义服务

// 定义通用的 Grpc 服务

service CommonService {
    // 处理请求
    rpc handle (EmployeeRequest) returns (EmployeeResponse) {
    }
}

完整示例

//指定proto3格式
syntax = "proto3";
//一些生成代码的设置
option java_package = "cn.com.yd.commons.grpc";
option java_outer_classname = "GrpcService";
option java_multiple_files = true;

//定义服务
service CommonService {
    // 处理请求
    rpc handle (EmployeeRequest) returns (EmployeeResponse) {
    }
}

//定义一个请求
message EmployeeRequest {
    string _id = 1; //主键
    string name = 2; //姓名
    sint32 tall = 3; //身高,单位cm,大于0
    sint32 age = 4; //年龄,大于0
    double weight = 5; //体重,单位kg,大于0
    Gender gender = 6; //性别
    //google.type.Date birthDate = 7;//出生日期
    google.protobuf.Timestamp regist_time = 10; //注册日期

  enum Corpus {
    UNIVERSAL = 0;
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }
  Corpus corpus = 11;
}

//定义一个响应
message EmployeeResponse {
    string msg = 1; //响应消息
    bool state = 2; //响应状态true|false
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值