Protocol 编码
为了实现跨语言的远程你调用,Google使用了一种统一的编码方式,可根据指定的.proto文件生成对应的消息体、请求Request和响应Response.
可以简单理解为根据不同的语言生成对应的代码
Protocol Buffters编译器
可从官网上下载对应的Protocol Buffters编译器,并使用指定生成对应的代码https://github.com/protocolbuffers/protobuf/releases
根据不同的开发环境下载对应的版本,这里以win版本作为案例.将下载的文件解压,并配置对应的环境变量
这里介绍一些
常用的指令
指令 | 说明 |
---|---|
–cpp_out=OUT_DIR | 生成C++代码 |
–java_out=OUT_DIR | 生成Java代码 |
–js_out=OUT_DIR | 生成Js代码 |
–kotlin_out=OUT_DIR | 生成kotlin代码 |
–php_out=OUT_DIR | 生成php代码 |
–python_out=OUT_DIR | 生成py代码 |
–ruby_out=OUT_DIR | 生成rb代码 |
# 这里以生成java为例,在当前目录生成(需要提前写好.proto文件)
protoc --ruby_out=./ ./MyPtoto.proto
*** 注意,除了需要安装Protocol Buffters,还有安装对应的语法插件,比如使用java就要在maven里安装protobuf-java支持库,用来生成对应的支持文件,具体安装方法在后面的开发语言篇中***
proto语法
生成代码之前需要定义好对应的生成规则,也就是grpc通讯的消息体、请求和响应格式
基础语法结构
1.1 语法声明
每个 .proto
文件都需要指定语法版本,通常使用 proto3
:
syntax = "proto3";
1.2 包声明
指定包名,类似于命名空间,用于避免消息或服务名称冲突:
package com.example.myapp;
1.3 导入其他 .proto
文件
使用 import
语句导入其他 .proto
文件中的定义:
import "other.proto";
1.4 定义消息
消息是 Protocol Buffers 的核心,用来定义数据结构。消息中可以包含字段,每个字段都有一个名称、类型和唯一的标识号
message 消息体名 {
int32 id = 1; // 一个整型字段,编号1
string name = 2; // 一个字符串字段,编号2
bool is_active = 3; // 一个布尔字段,编号3
}
1.5 定义服务
服务是 gRPC 的核心,定义了远程过程调用(RPC)的接口。每个服务包含多个 RPC 方法。根据通讯方式的不同,服务也分为4种
- 单一响应:发送一个请求得到一个响应
- 使用场景:调用的远程方法是一个计算函数,只会返回一次结果
service 服务名 {
rpc 服务方法名 (请求消息体) returns (响应消息体);
}
- 客户端流式:发送多个请求,直到客户端确定complete,服务端才响应
- 使用场景:调用的远程方法需要传递一个文件,这个文件需要分批上传
service 服务名 {
rpc 服务方法名 (stream 请求消息体) returns (响应消息体);
}
- 服务端流式:发送一个请求,服务端返回多个响应,直到服务端complete
- 使用场景:调用的远程方法返回一个文件,这个文件分批返回
service 服务名 {
rpc 服务方法名 (请求消息体) returns (stream 响应消息体);
}
- 双向流式:发送多个请求,直到客户端确定complete,服务端才响应,服务端返回多个响应,直到服务端complete
- 使用场景:调用的远程方法是一个计算函数,只会返回一次结果
service 服务名 {
rpc 服务方法名 (stream 请求消息体) returns (stream 响应消息体);
}
个人经验:一般直接定义双向流式,然后在代码里面进行控制.比如我定义的是一个双向流式,但实际上业务中仅使用到单向,那么请求和响应的时候发出一个数据就直接complete结束就行
案例
syntax = "proto3";
package com.llllluuusa;
service StudyService {
rpc StudyMethod(StudyRequest) returns (StudyResponse);
}
message StudyRequest {
string message = 1;
}
message StudyResponse {
string reply = 1;
}
消息类型
字段定义了消息的数据成员,格式如下:
<类型> <字段名> = <标签>;
2.1标量类型
常用的标量类型包括:
- 整数类型:
int32
、int64
、uint32
、uint64
、sint32
、sint64
、fixed32
、fixed64
、sfixed32
、sfixed64
- 浮点类型:
float
、double
- 布尔类型:
bool
- 字符串类型:
string
- 字节类型:
bytes
2.2数组类型
使用 repeated
定义可以重复的字段,相当于列表或数组。
message Group {
repeated string members = 1;
}
2.3键值类型
使用 map
定义键值对集合。
message Dictionary {
map<string, int32> word_count = 1;
}
2.4互斥类型
oneof
用于定义互斥的字段,某一时刻只能设置其中一个
message SampleMessage {
oneof test_oneof {
string name = 4;
int32 id = 5;
}
}
个人经验:一般使用string类型,数据用json格式,这样方便统一数据格式转换,二是json格式相对其他格式序列化后所占用的空间小,传输数据更方便