本文较为简略,只是介绍了一个大概的流程,具体的开发后面博文可见。
一、定义:定义一个服务,指定其能被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,同时运行一个grpc服务器来处理客户端调用。客户端拥有一个文件(存根)可以访问服务端。
二、依赖:protocol buffers,谷歌开源的结构数据序列化机制(类似json),通过使用proto file创建grpc服务,protocol buffers 消息类型来定义方法参数和返回类型。。我们在使用gprc时,使用版本是proto 3,针对c++和Java还有go都有支持。
三、测试环境:git、Java需要jdk
四、测试:
一、下载grpc源码:
git clone https://github.com/grpc/grpc-java.git
cd grpc-java/examples
二、定义服务:通过proto buffers 的proto 3 版本实现,proto buffer使用接口定义语言来实现服务方法、请求参数、返回类型。客户端和服务端均使用服务定义生成的接口代码。
在helloworld.proto 使用Greeter
服务有一个方法 SayHello
,可以让服务端从远程客户端接收一个包含用户名的 HelloRequest
消息后,在一个 HelloReply
里发送回一个 Greeter
。
syntax = "proto3";
option java_package = "io.grpc.examples";
package helloworld;
// The greeter service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
三、生成grpc代码:
使用编译器protoc生成客户端和服务器端所需的代码。
生成HelloRequest.java, HelloResponse.java和其他文件包含所有 protocol buffer 用来填充、序列化和提取 HelloRequest
和 HelloReply
消息类型的代码。
GreeterGrpc.java, 包含 (还有其他有用的代码):
Greeter
服务端需要实现的接口
public static interface Greeter {
public void sayHello(Helloworld.HelloRequest request,
StreamObserver<Helloworld.HelloReply> responseObserver);
}
客户端用来与 Greeter
服务端进行对话的 存根
类。就像你所看到的,异步存根也实现了 Greeter
接口。
public static class GreeterStub extends AbstractStub<GreeterStub>
implements Greeter {
...
}
四、写一个服务器
GreeterImpl.java
准确地实现了 Greeter
服务所需要的行为。 正如你所见,GreeterImpl
类通过实现 sayHello
方法,实现了从 IDL生成的GreeterGrpc.Greeter
接口 。
@Override
public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
sayHello
有两个参数:
HelloRequest
,请求。-
StreamObserver<HelloReply>
: 应答观察者,一个特殊的接口,服务器用应答来调用它。为了返回给客户端应答并且完成调用:
1.用我们的激动人心的消息构建并填充一个在我们接口定义的 HelloReply
应答对象。
2.将 HelloReply
返回给客户端,然后表明我们已经完成了对 RPC 的处理.
五、服务端实现
确认服务在服务端有可用合理的 gRPC 服务器,将我们实现的 Greeter
服务绑定到一个端口。然后我们启动服务器:服务器现在已准备好从 Greeter
服务客户端接收请求。我们将在具体语言对应的文档里更深入地了解这所有的工作是怎样进行的。
/* The port on which the server should run */
private int port = 50051;
private Server server;
private void start() throws Exception {
server = ServerBuilder.forPort(port)
.addService(GreeterGrpc.bindService(new GreeterImpl()))
.build()
.start();
logger.info("Server started, listening on " + port);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
// Use stderr here since the logger may has been reset by its JVM shutdown hook.
System.err.println("*** shutting down gRPC server since JVM is shutting down");
HelloWorldServer.this.stop();
System.err.println("*** server shut down");
}
});
}
六、写一个客户端
客户端的 gRPC 非常简单。在这一步,我们将用生成的代码写一个简单的客户程序来访问我们在上一节里创建的 Greeter
服务器。
1.连接服务:连接 Greeter
服务器。我们需要创建一个 gRPC 频道,指定我们要连接的主机名和服务器端口。然后我们用这个频道创建存根实例。
private final ManagedChannel channel;
private final GreeterGrpc.GreeterBlockingStub blockingStub;
public HelloWorldClient(String host, int port) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext(true)
.build();
blockingStub = GreeterGrpc.newBlockingStub(channel);
}
2.调用 RPC:现在我们可以联系服务并获得一个 greeting,
- 我们创建并填充一个
HelloRequest
发送给服务。 - 我们用请求调用存根的
SayHello()
,如果 RPC 成功,会得到一个填充的HelloReply
,从其中我们可以获得 greeting。
HelloRequest req = HelloRequest.newBuilder().setName(name).build();
HelloReply reply = blockingStub.sayHello(req);
七、运行
不同的语言间的互操作性,即在不同的语言运行客户端和服务端。每个服务端和客户端使用从同一过 proto 文件生成的接口代码,则意味着任何 Greeter
客户端可以与任何 Greeter
服务端对话。
Java 首先运行服务端:你可以从 examples
目录构建并运行服务端。
首先构建客户端和服务端:
$ ../gradlew -PskipCodegen=true installDist
然后运行服务端,服务端将监听 50051 :
$ ./build/install/grpc-examples/bin/hello-world-server
一旦服务器在运行,在其他的终端窗口运行客户端并确认它收到一个消息。你可以在 examples
目录下构建并运行客户端。假如你还没有构建客户端,可以使用如下命令:
$ ../gradlew -PskipCodegen=true installDist
然后运行客户端:
$ ./build/install/grpc-examples/bin/hello-world-client