转载请注明出处:
在 proto 文件中,service 用于定义一组 RPC 方法,在服务端实现这些方法,并在客户端调用这些方法进行远程过程调用。
service 的定义方式如下:
service MyService { rpc MyMethod(MyRequest) returns (MyResponse); }
其中,MyService 是服务的名称,MyMethod 是方法的名称,MyRequest 和 MyResponse 分别是输入和输出消息的类型。
在 Java 中,使用 protoc 工具生成代码后,可以通过继承自动生成的 MyServiceGrpc 类来实现服务端和客户端。
例如,服务端可以创建一个继承自 MyServiceGrpc.MyServiceImplBase 的类,实现 MyMethod 方法,处理客户端发送过来的 MyRequest 消息,并返回 MyResponse 响应消息。示例代码如下:
class MyServerImpl extends MyServiceGrpc.MyServiceImplBase { @Override public void myMethod(MyRequest request, StreamObserver<MyResponse> responseObserver) { // 处理请求消息 ... // 发送响应消息 MyResponse response = MyResponse.newBuilder().build(); responseObserver.onNext(response); responseObserver.onCompleted(); } }
然后在启动服务器时将该服务添加到 ServerBuilder 中即可,示例代码如下:
Server server = ServerBuilder.forPort(PORT) .addService(new MyServerImpl()) .build(); server.start();
在客户端中,通过创建一个 MyServiceGrpc.MyBlockingStub 或 MyServiceGrpc.MyStub 对象来调用 MyMethod 方法。MyBlockingStub 提供了同步的阻塞式调用方式,而 MyStub 提供了异步的非阻塞式调用方式。示例代码如下:
ManagedChannel channel = ManagedChannelBuilder.forAddress(address, port).usePlaintext().build(); MyServiceGrpc.MyBlockingStub blockingStub = MyServiceGrpc.newBlockingStub(channel); MyServiceGrpc.MyStub asyncStub = MyServiceGrpc.newStub(channel); MyRequest request = MyRequest.newBuilder().build(); MyResponse response = blockingStub.myMethod(request); asyncStub.myMethod(request, new StreamObserver<MyResponse>() { @Override public void onNext(MyResponse response) { // 处理响应消息 } @Override public void onError(Throwable t) { // 处理异常 } @Override public void onCompleted() { // 完成回调 } });
客户端发送请求时,首先创建一个 MyRequest 消息对象,并将其传递给对应的 BlockingStub 或 Stub 调用方法(例如 myMethod 方法)。BlockingStub 方法会直接返回响应消息,而 Stub 方法会使用 StreamObserver 来接收异步的响应消息或错误。
在服务端接收到请求时,会根据请求消息里的方法名称调用相应的处理方法,并将请求消息作为参数传递给该方法提取所需信息并进行处理,然后返回所需的响应消息。整个过程中,双方都需要遵守相应的协议和格式规范。
如果 proto 文件中没有定义 service,则使用 protoc 直接生成 Java 文件时并不会生成 gRPC 相关的类和方法。
gRPC 的实现是基于 proto 文件中所定义的 Service,因此必须在 proto 文件中定义 Service 才能生成 gRPC 相关的类。
proto 文件中service的示例:
syntax = "proto3"; package example; message Greeting { string name = 1; } // 添加新的服务 Greeter service Greeter { rpc SayHello(Greeting) returns (Greeting) {} }
标签: protobuf