一、简介
我们之前完成了一个基本的客户端和服务端通过grpc来调用的代码功能。我们使用的其实是一种最简单的通信方式,貌似和以前的spring mvc没啥区别,那么grpc作为一个基于http的双工的设计,肯定不是简单的只支持这样的能力。
下面我们就来看看grpc所支持的这四种传输模式。
二、grpc的通信模式
grpc一种支持四种通信模式。
1. 简单rpc也叫一元rpc (Unary RPC)
2. 服务端流式RPC (Server Streaming RPC)
3. 客户端流式RPC (Client Streaming RPC)
4. 双向流RPC (Bi-directional Stream RPC)
下面我们就一一来介绍一下。
我们先说明一下,区分这几种通信模式的源头就在于proto的语法定义上。
1、简单RPC(一元RPC)
之前我们写的那种方式就叫做简单rpc。
他的特点就是客户端发起请求,然后服务端响应,在响应之前客户端是阻塞等待的。一般我们用的就是这种。当然你可以说有异步的模式,但是要想获取结果,也是要阻塞等待的。

他的语法定义就是我们之前用的那种。
/* 简单rpc,参数为HelloRequest类型,返回类型为HelloResponse */
rpc hello(HelloRequest) returns (HelloResponse){}
/* 多值rpc,参数为ManyHelloRequest类型,返回类型为ManyHelloResponse */
rpc manyHello(ManyHelloRequest) returns (ManyHelloResponse){}
2、服务端流式RPC
他的特点是客户端发起一个请求对象,服务端可以回传多个结果对象。
注意,这个返回多个结果对象指的不是返回多个内容封装在一个集合里面返回(这种还是一个返回值),而是在不同的时刻各自返回该时刻的不同的内容,他是一个流式的一个形式。所以他一定是在这个交互的过程中保持这个连接不断的,换言之他是一个长连接。
你可以用来做那种类似sse的服务端推流的场景,股票一类的。

他的语法定义为
// 服务端流式rpc,参数为HelloRequest类型,返回类型为HelloResponse,但是返回值这里要加一个stream关键字,标识服务端返回的格式为流
rpc c2ss(HelloRequest) returns (stream HelloResponse){}
我们来按照这个proto定义来生成一下结果,然后来编写客户端和服务端。
2.1、服务端代码
// 服务端实现类
public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {
private static final String RES_PREFIX = "server#";
@Override
public void c2ss(HelloProto.HelloRequest request, StreamObserver<HelloProto.HelloResponse> responseObserver) {
//1 接受client的请求参数
String requestName = request.getName();
//2 做业务处理
System.out.println("name: " + requestName);
//3 根据业务处理的结果,提供响应,推送多个给客户端
for (int i = 0; i < 9; i++) {
HelloProto.HelloResponse.Builder builder = HelloProto.HelloResponse.newBuilder();
builder.setResult("服务端处理的结果:" + i);
HelloProto.HelloResponse helloResponse = builder.build();
responseObserver.onNext(helloResponse);
try {
// 暂停一秒推送数据给客户端
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
responseObserver.onCompleted();
}
@Override
public void manyHello(HelloProto.ManyHelloRequest request, StreamObserver<HelloProto.ManyHelloResponse> responseObserver) {
//1.接受client的请求参数,我们看到此时就是一个nameList的集合了,因为它被repeated修饰了,当然他的类型是ProtocolStringList,是grpc自己的类型
ProtocolStringList requestNamesList = request.getNamesList();
//2.业务处理
System.out.println("请求参数为:" + requestNamesList);
// 给返回值的name都加一个前缀
List<String> responseNamesList = new ArrayList<>();
for (String requestName : requestNamesList) {
responseNamesList.add(RES_PREFIX + requestName);
}
//3.封装响应
//3.1 创建相应对象的构造者
HelloProto.ManyHelloResponse.Builder builder = HelloProto.ManyHelloResponse.newBuilder();
//3.2 填充数据,多个值要通过addAllResult,或者是下标的方式添加
builder.addAllResult(responseNamesList);
// for (int i = 0; i < requestNamesList.size(); i++) {
// builder.setResult(i, requestNamesList.get(i));
// }
//3.3 封装响应
HelloProto.ManyHelloResponse helloResponse = builder.build();
// 4. 响应client
responseObserver.onNext(helloResponse);
// 5. 响应完成
responseObserver.onCompleted();
}
/*
1. 接受client提交的参数 request.getParameter()
2. 业务处理 service+dao 调用对应的业务功能。
3. 提供返回值
*/
@Override
public void hello(HelloProto.HelloRequest request, StreamObserver<HelloProto.HelloResponse> responseObserver) {
//1.接受client的请求参数
String name = request.getName();
//2.业务处理
System.out.println("name parameter "+name);
//3.封装响应
//3.1 创建相应对象的构造者
HelloProto.HelloResponse.Builder builder = HelloProto.HelloResponse.newBuilder();
//3.2 填充数据
builder.setResult("hello method invoke ok");
//3.3 封装响应
HelloProto.HelloResponse helloResponse = builder.build();
// 4. 响应client
responseObserver.onNext(helloResponse);
// 5. 响应完成
responseObserver.onCompleted();
}
}
服务端发布依然是:
public static void main(String[] args) throws IOException, InterruptedException {
//1. 绑定端口
ServerBuilder<?> serverBuilder = ServerBuilder.forPort(9000);
//2. 发布服务
serverBuilder.addService(new HelloServiceImpl

最低0.47元/天 解锁文章
1613

被折叠的 条评论
为什么被折叠?



