转自:http://www.saily.top/2017/07/23/netty5/

gRPC

Define your service using Protocol Buffers, a powerful binary serialization toolset and language

gRPC是基于Protobuf开发的RPC框架,简化了protobuf的开发,提供了服务端和客户端网络交互这一块的代码。

Demo

照着https://grpc.io/docs/quickstart/java.html测试一下官方的Demo。

记得要把Update a gRPC service部分做了。

gRPC整合Gradle与代码生成

https://github.com/grpc/grpc-java
这个是gRPC-java项目,先引入gRPC的依赖。

1
2
3
compile 'io.grpc:grpc-netty:1.4.0'
compile 'io.grpc:grpc-protobuf:1.4.0'
compile 'io.grpc:grpc-stub:1.4.0'

然后配置gradle的grpc插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apply plugin: 'java'
apply plugin: 'com.google.protobuf' buildscript {
repositories {
mavenCentral()
}
dependencies {
// ASSUMES GRADLE 2.12 OR HIGHER. Use plugin version 0.7.5 with earlier
// gradle versions
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'
}
} protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.2.0"
}
plugins {
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.4.0'
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}

后面直接用gradle的任务就可以生成代码了。

gRPC提供了3种传输层的实现

  • gRPC comes with three Transport implementations:

    1. The Netty-based transport is the main transport implementation based on Netty. It is for both the client and the server.
    2. The OkHttp-based transport is a lightweight transport based on OkHttp. It is mainly for use on Android and is for client only.
    3. The inProcess transport is for when a server is in the same process as the client. It is useful for testing.

https://github.com/google/protobuf-gradle-plugin

The Gradle plugin that compiles Protocol Buffer (aka. Protobuf) definition files (*.proto) in your project. There are two pieces of its job:

  1. It assembles the Protobuf Compiler (protoc) command line and use it to generate Java source files out of your proto files.
  2. It adds the generated Java source files to the input of the corresponding Java compilation unit (sourceSet in a Java project; variant in an Android project), so that they can be compiled along with your Java sources.

实战

配置好后,进行一个演示

src/main/proto新建一个文件Student.proto

gradle插件默认从src/main/proto找proto源文件进行代码生成,这里有提到,而且这个路径的配置是可以修改的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
syntax = "proto3";

package com.sail.proto;

option java_package = "com.sail.proto";
option java_outer_classname = "StudentProto";
option java_multiple_files = true; service StudentService {
rpc GetRealNameByUsername(MyRequest) returns (MyResponse) {} rpc GetStudentsByAge(StudentRequest) returns (stream StudentResponse) {} rpc GetStudentsWrapperByAges(stream StudentRequest) returns (StudentResponseList) {} rpc BiTalk(stream StreamRequest) returns (stream StreamResponse) {}
} message MyRequest {
string username = 1;
} message MyResponse {
string realname = 2;
} message StudentRequest {
int32 age = 1;
} message StudentResponse {
string name = 1;
int32 age = 2;
string city = 3;
} message StudentResponseList {
repeated StudentResponse studentResponse = 1;
} message StreamRequest {
string request_info = 1;
} message StreamResponse {
string response_info = 1;
}

然后执行gradle generateProto,生成的代码默认是放在/build目录下,我们手动拷贝到src/main/java

实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package com.sail.grpc;

import com.sail.proto.*;
import io.grpc.stub.StreamObserver; import java.util.UUID; /**
* @author yangfan
* @date 2017/08/01
*/
public class StudentServiceImpl extends StudentServiceGrpc.StudentServiceImplBase { @Override
public void getRealNameByUsername(MyRequest request, StreamObserver<MyResponse> responseObserver) {
System.out.println("接收到客户端信息: " + request.getUsername());
responseObserver.onNext(MyResponse.newBuilder().setRealname("张三").build());
responseObserver.onCompleted();
} /**
* 接收StudentRequest参数
* 返回stream的StudentResponse
*/
@Override
public void getStudentsByAge(StudentRequest request, StreamObserver<StudentResponse> responseObserver) {
System.out.println("接收到客户端信息:" + request.getAge()); responseObserver.onNext(StudentResponse.newBuilder().setName("张三").setAge(20).setCity("北京").build());
responseObserver.onNext(StudentResponse.newBuilder().setName("李四").setAge(30).setCity("天津").build());
responseObserver.onNext(StudentResponse.newBuilder().setName("王五").setAge(40).setCity("成都").build());
responseObserver.onNext(StudentResponse.newBuilder().setName("赵六").setAge(50).setCity("深圳").build()); responseObserver.onCompleted();
} /**
* 接收stream的StudentRequest参数
* 返回StudentResponseList
*/
@Override
public StreamObserver<StudentRequest> getStudentsWrapperByAges(StreamObserver<StudentResponseList> responseObserver) {
return new StreamObserver<StudentRequest>() { @Override
public void onNext(StudentRequest value) {
System.out.println("onNext: " + value.getAge());
} @Override
public void onError(Throwable t) {
System.out.println(t.getMessage());
} @Override
public void onCompleted() {
StudentResponse studentResponse = StudentResponse.newBuilder().setName("张三").setAge(20).setCity("西安").build();
StudentResponse studentResponse2 = StudentResponse.newBuilder().setName("李四").setAge(30).setCity("成都").build(); StudentResponseList studentResponseList = StudentResponseList.newBuilder()
.addStudentResponse(studentResponse).addStudentResponse(studentResponse2).build(); responseObserver.onNext(studentResponseList);
responseObserver.onCompleted();
}
};
} /**
* 双向流式数据传递
*/
@Override
public StreamObserver<StreamRequest> biTalk(StreamObserver<StreamResponse> responseObserver) {
return new StreamObserver<StreamRequest>() {
@Override
public void onNext(StreamRequest value) {
System.out.println(value.getRequestInfo()); responseObserver.onNext(StreamResponse.newBuilder().setResponseInfo(UUID.randomUUID().toString()).build());
} @Override
public void onError(Throwable t) {
System.out.println(t.getMessage());
} @Override
public void onCompleted() {
responseObserver.onCompleted();
}
};
}
}

服务器端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.sail.grpc;

import io.grpc.Server;
import io.grpc.ServerBuilder; import java.io.IOException; /**
* @author yangfan
* @date 2017/08/01
*/
public class GrpcServer { private Server server; private void start() throws IOException {
this.server = ServerBuilder.forPort(8899).addService(new StudentServiceImpl()).build().start();
System.out.println("server started!"); // 这里在关闭JVM的时候会执行JVM回调钩子
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("关闭jvm");
GrpcServer.this.stop();
})); System.out.println("执行到这里");
} private void stop() {
if (server != null) {
this.server.shutdown();
}
} private void awaitTermination() throws InterruptedException {
if (server != null) {
this.server.awaitTermination();
}
} public static void main(String[] args) throws InterruptedException, IOException { GrpcServer grpcServer = new GrpcServer();
grpcServer.start();
grpcServer.awaitTermination(); }
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package com.sail.grpc;

import com.sail.proto.*;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.StreamObserver; import java.time.LocalDateTime;
import java.util.Iterator; /**
* @author yangfan
* @date 2017/08/01
*/
public class GrpcClient {
public static void main(String[] args) {
ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 8899)
.usePlaintext(true).build(); StudentServiceGrpc.StudentServiceBlockingStub blockingStub = StudentServiceGrpc.newBlockingStub(managedChannel);
StudentServiceGrpc.StudentServiceStub stub = StudentServiceGrpc.newStub(managedChannel);
MyResponse myResponse = blockingStub.getRealNameByUsername(MyRequest.newBuilder().setUsername("zhangsan").build()); System.out.println(myResponse.getRealname()); System.out.println("----------------"); Iterator<StudentResponse> iter = blockingStub.getStudentsByAge(StudentRequest.newBuilder().setAge(20).build()); while (iter.hasNext()) {
StudentResponse studentResponse = iter.next(); System.out.println(studentResponse.getName() + ", " + studentResponse.getAge() + ", " + studentResponse.getCity()); } System.out.println("----------------"); // getStudentsWrapperByAges的调用代码 StreamObserver<StudentResponseList> studentResponseListStreamObserver = new StreamObserver<StudentResponseList>() {
@Override
public void onNext(StudentResponseList value) {
value.getStudentResponseList().forEach(studentResponse -> {
System.out.println(studentResponse.getName() + ", " + studentResponse.getAge() + ", " + studentResponse.getCity());
System.out.println("*******");
});
} @Override
public void onError(Throwable t) {
System.out.println(t.getMessage());
} @Override
public void onCompleted() {
System.out.println("completed!");
}
}; // 只要客户端是以流式发送请求,那么一定是异步的
StreamObserver<StudentRequest> studentRequestStreamObserver = stub.getStudentsWrapperByAges(studentResponseListStreamObserver);
// 发送多条数据
studentRequestStreamObserver.onNext(StudentRequest.newBuilder().setAge(20).build());
studentRequestStreamObserver.onNext(StudentRequest.newBuilder().setAge(30).build());
studentRequestStreamObserver.onNext(StudentRequest.newBuilder().setAge(40).build());
studentRequestStreamObserver.onNext(StudentRequest.newBuilder().setAge(50).build());
studentRequestStreamObserver.onCompleted(); // 以上代码是没有输出结果的,因为stub是异步的,所以当执行完onCompleted的时候程序就已经结束了,还没有来得及发送请求
// 现在加入以下代码,让程序多运行一会
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
e.printStackTrace();
} // 双向数据流的调用 StreamObserver<StreamRequest> requestStreamObserver = stub.biTalk(new StreamObserver<StreamResponse>() {
@Override
public void onNext(StreamResponse value) {
System.out.println(value.getResponseInfo());
} @Override
public void onError(Throwable t) {
System.out.println(t.getMessage());
} @Override
public void onCompleted() {
System.out.println("onCompleted!");
}
}); for (int i = 0; i < 10; i++) {
requestStreamObserver.onNext(StreamRequest.newBuilder().setRequestInfo(LocalDateTime.now().toString()).build());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} }
} }

Netty-gRPC介绍和使用的更多相关文章

  1. Netty简单介绍(非原创)

    文章大纲 一.Netty基础介绍二.Netty代码实战三.项目源码下载四.参考文章   一.Netty基础介绍 1. 简介 官方定义为:”Netty 是一款异步的事件驱动的网络应用程序框架,支持快速地 ...

  2. NETTY 编码器介绍

    1. 背景 1.1. 编解码技术 通常我们也习惯将编码(Encode)称为序列化(serialization),它将对象序列化为字节数组,用于网络传输.数据持久化或者其它用途. 反之,解码(Decod ...

  3. 【Netty】Netty核心组件介绍

    一.前言 前篇博文体验了Netty的第一个示例,下面接着学习Netty的组件和其设计. 二.核心组件 2.1. Channel.EventLoop和ChannelFuture Netty中的核心组件包 ...

  4. grpc介绍

    grpc入门(一) 一.什么是grpc grpc是谷歌开源的一款高性能的rpc框架 (https://grpc.io),可以使用protocol buffers作为IDL(Interface Defi ...

  5. Netty:Netty的介绍以及它的核心组件(一)—— Channel

    1. Netty 介绍 Netty 是一个无阻塞的输入/输出(NIO)框架,它使开发低级网络服务器和客户端变得相对简单.Netty为需要在套接字级别上工作的开发人员提供了令人难以置信的强大功能,例如, ...

  6. Netty组件介绍(转)

    http://www.tuicool.com/articles/mEJvYb 为了更好的理解和进一步深入Netty,我们先总体认识一下Netty用到的组件及它们在整个Netty架构中是怎么协调工作的. ...

  7. [置顶] Netty学习总结(1)——Netty入门介绍

    1.Netty是什么? Netty是一个基于JAVA NIO类库的异步通信框架,它的架构特点是:异步非阻塞.基于事件驱动.高性能.高可靠性和高可定制性. 2.使用Netty能够做什么? 开发异步.非阻 ...

  8. go gRPC介绍, demo

    参考文章: 1. https://www.cnblogs.com/kaixinyufeng/p/9651513.html 2. http://jia-shun.cn/2018/08/12/gRPC/ ...

  9. Netty核心组件介绍及手写简易版Tomcat

    Netty是什么: 异步事件驱动框架,用于快速开发高i性能服务端和客户端 封装了JDK底层BIO和NIO模型,提供高度可用的API 自带编码解码器解决拆包粘包问题,用户只用关心业务逻辑 精心设计的Re ...

  10. Netty:Netty的介绍以及它的核心组件(三)—— 事件和ChannelHandler

    Netty 使用异步事件驱动(Asynchronous Event-Driven)的应用程序范式,因此数据处理的管道(ChannelPipeLine)是经过处理程序(ChannelHandler)的事 ...

随机推荐

  1. 事件分发机制 事件拦截 滑动冲突 MD

    目录 事件分发机制分析案例 默认行为 试验 0 结论 dispatchTouchEvent 返回 true 试验 1 试验 2 结论 onInterceptTouchEvent 返回 true 试验 ...

  2. Centos6.4下安装protobuf-c问题及解决办法

    1.前言 protobuf是Google提供的结构持久化工具,类型XML,但要比XML更加灵活,效率要高.protobuf当初支持C++.JAVA和Python,后来有了支持C语言的Protobuf- ...

  3. thinkcmf 角色授权支持分类

    ThinkCMF中的权限是以后台菜单为基础来进行设置的(menu table),即如果你需要一个自定义的权限,那么你需要在后台菜单里添加一项菜单,然后在角色管理里可以针对角色进行授权   而现在遇到一 ...

  4. 利用OSG实现模拟飞机尾迹-粒子系统

    利用OSG实现模拟飞机尾迹-粒子系统 粒子系统简介:         粒子系统是用于不规则模糊物体建模及图像生成的一种方法.         粒子系统是一种过程模型,即利用各种计算过程生成模型各个体素 ...

  5. 【Python】torrentParser1.01

    在昨天的版本上做了一些改进,如增加getAll,修改getSingleFileName等 代码: #-------------------------------------------------- ...

  6. C#.NET常见问题(FAQ)-如何让控件或者窗体本身全屏

    初始化的时候保存控件的原始尺寸,然后通过Dock属性调节   注意如果你的控件是放在容器中的,那么对应设置的也要是容器的Dock属性   全屏的效果如下图所示   更多教学视频和资料下载,欢迎关注以下 ...

  7. Selenium2(WebDriver)总结(三)---元素定位方法

    元素定位的重要性不言而喻,如果定位不到元素谈何操作元素呢,webdrvier提供了很多种元素定位方法,如ID,Name,xpath,css,tagname等. 例如需要定位如下元素: <inpu ...

  8. hive中简单介绍分区表(partition table)——动态分区(dynamic partition)、静态分区(static partition)

    一.基本概念 hive中分区表分为:范围分区.列表分区.hash分区.混合分区等. 分区列:分区列不是表中的一个实际的字段,而是一个或者多个伪列.翻译一下是:“在表的数据文件中实际上并不保存分区列的信 ...

  9. Mybatis 自动生成代码,数据库postgresql

    最近做了一个项目,使用Mybatis自动生成代码,下面做一下总结,被以后参考: 一.提前准备: 1.工具类:mybatis-generator-core-1.3.2.jar 2.postgresql驱 ...

  10. NGINX源码分析——概览

    一.概况 Nginx可以开启多个进程,每个进程拥有最大上限128个子线程以及一定的可用连接数.最大客户端连接数等于进程数与连接数的乘积,连接是在主进程中初始化的,一开始所有连接处于空闲状态.每一个客户 ...