前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一步步完成gRPC 示例

一步步完成gRPC 示例

作者头像
孟君
发布2019-09-17 16:18:34
4.8K2
发布2019-09-17 16:18:34
举报
文章被收录于专栏:孟君的编程札记

本文将一步步完成一个gRPC的示例。文章从如下几个部分来加以说明:

  • 根据proto自动生成代码 - 编写proto文件,并根据工具在window下自动生成gRPC所需代码
  • 代码组成 - 给出Maven工程的模块化结构组成,并在每个模块中一步步实现代码
  • 测试 - 对编写的代码进行测试,包括Server启动并绑定服务、Client连接并调用服务
  • 小结 - 针对本文的内容进行简单的介绍

下面就一步步来完成每一个部分~

一、根据proto自动生成代码

1.1 定义服务接口

gRPC 默认使用 protocol buffers 作为接口定义语言,来描述服务接口和有效载荷消息结构。 更多的proto3文档信息,参考https://developers.google.com/protocol-buffers/docs/proto3

  • hello.proto
代码语言:javascript
复制
syntax = "proto3";

package com.xxx.tutorial.demo.grpc;

option java_multiple_files = true;
option java_package = "com.xxx.tutorial.demo.model";  
option java_outer_classname = "Hello";

message HelloRequest{  
    string name  = 1;  
    int32 id    = 2;  
}  
message HelloResponse{  
    string message = 1;  
}
  • hello_service.proto
代码语言:javascript
复制
syntax = "proto3";

package com.xxx.tutorial.demo.grpc;


option java_multiple_files = true;
option java_package = "com.xxx.tutorial.demo.service"; 
option java_outer_classname = "GreetingService";

import "hello.proto";

service HelloService{  
    rpc sayHello(HelloRequest) returns (HelloResponse);  
}

1.2 产生proto文件对应代码

可以访问网址【https://github.com/google/protobuf/releases】查看不同版本代码生成器,本文使用的版本为protoc-3.1.0-win32.zip,可以访问如下地址下载,

【https://github.com/google/protobuf/releases/download/v3.1.0/protoc-3.1.0-win32.zip】

  • 下载好之后,解压缩,并把proto文件防止到bin目录中
  • 执行protoc.exe --java_out=./ *.proto生成代码
代码语言:javascript
复制
F:\JavaDeveloper\rpc\gRpc\protoc-3.1.0-win32\bin>protoc.exe --java_out=./ *.proto

执行上述命令之后,在bin目录下会生成代码(包含包名), 如:

具体modelservice包中的代码截图如下:

注意:

上述生成了消息对象等相关代码但是还不包含rpc服务所需要的通信代码

1.3 生成rpc通信代码

rpc通信代码需要protoc-gen-grpc-java 插件来完成,可以访问如下网址下载:【protoc-gen-grpc-java-0.13.2-windows-x86_64.exe】

将下载的protoc-gen-grpc-java-0.13.2-windows-x86_64.exe放到protoc-3.1.0-win32下的bin目录中。如:

执行如下语句即可~

protoc.exe --plugin=protoc-gen-grpc-java=protoc-gen-grpc-java-0.13.2-windows-x86_64.exe --grpc-java_out=./ *.proto

如:

代码语言:javascript
复制
F:\JavaDeveloper\rpc\gRpc\protoc-3.1.0-win32\bin>protoc.exe --java_out=./ *.proto
F:\JavaDeveloper\rpc\gRpc\protoc-3.1.0-win32\bin>protoc.exe --plugin=protoc-gen-grpc-java=protoc-gen-grpc-java-0.13.2-windows-x86_64.exe --grpc-java_out=./ *.proto
F:\JavaDeveloper\rpc\gRpc\protoc-3.1.0-win32\bin>

可以看到在service包中多了一个HelloServiceGrpc.java文件。

该文件在后续服务实现的时候需要用到。

至此,根据proto文件产生Java代码部分就完成了。接下来,要做的就是编写服务实现、服务器代码以及客户端调用接口的代码等~

二、代码组成

2.1 Maven工程结构

grpc-demo这个Maven工程主要包含四个模块,

  • grpc-demo-interface - 存放proto文件产生的代码
  • grpc-demo-service - 实现服务
  • grpc-demo-server - 简单服务器
  • grpc-demo-client - 简单的客户端

pom文件如下:

代码语言:javascript
复制
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.xxx.tutorial</groupId>
  <artifactId>grpc-demo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>
  <modules>
    <module>grpc-demo-server</module>
    <module>grpc-demo-client</module>
    <module>grpc-demo-interface</module>
    <module>grpc-demo-service</module>
  </modules>
</project>

Eclipse的工程目录结构如下:

2.2 grpc-demo-interface模块

直接将上述生成的代码,拷贝到src/main/java中,如

遇到“红叉叉”是因为,没有导入相关的jar包~ 在该模块下的pom.xml文件中添加相关的依赖包即可:

代码语言:javascript
复制
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.xxx.tutorial</groupId>
    <artifactId>grpc-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>grpc-demo-interface</artifactId>

  <dependencies>
    <dependency>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java</artifactId>
      <version>3.1.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/io.grpc/grpc-stub -->
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-stub</artifactId>
      <version>1.3.0</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-protobuf</artifactId>
      <version>1.3.0</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-netty</artifactId>
      <version>1.3.0</version>
    </dependency>
  </dependencies>
</project>

服务接口模块搞定,接下来要完成接口的实现。

2.3 grpc-demo-service模块

  • 添加grpc-demo-interface依赖
代码语言:javascript
复制
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.xxx.tutorial</groupId>
    <artifactId>grpc-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>grpc-demo-service</artifactId>

  <dependencies>
    <dependency>
      <groupId>com.xxx.tutorial</groupId>
      <artifactId>grpc-demo-interface</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
  </dependencies>
</project>
  • 编写服务接口实现类
代码语言:javascript
复制
package com.xxx.tutorial.demo.service.impl;

import java.util.logging.Logger;

import com.xxx.tutorial.demo.model.HelloRequest;
import com.xxx.tutorial.demo.model.HelloResponse;
import com.xxx.tutorial.demo.service.HelloServiceGrpc;

import io.grpc.stub.StreamObserver;

public class GreetingServiceImpl implements HelloServiceGrpc.HelloService {

  private static final Logger logger = Logger.getLogger(GreetingServiceImpl.class.getName());

  public void sayHello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {

    logger.info(String.format("sayHello方法调用的请求参数信息: name={%s}, id={%d}", request.getName(), request.getId()));

    HelloResponse reply = HelloResponse.newBuilder().setMessage(String.format("Hello, %s", request.getName()))
        .build();
    
    responseObserver.onNext(reply);
    responseObserver.onCompleted();
  }

}

2.4 grpc-demo-server模块

  • 添加grpc-demo-service依赖
代码语言:javascript
复制
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.xxx.tutorial</groupId>
    <artifactId>grpc-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>grpc-demo-server</artifactId>

  <dependencies>
    <dependency>
      <groupId>com.xxx.tutorial</groupId>
      <artifactId>grpc-demo-service</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
  </dependencies>
  
</project>
  • 编写Server代码
代码语言:javascript
复制
package com.xxx.tutorial.demo.server;

import java.io.IOException;
import java.util.logging.Logger;

import com.xxx.tutorial.demo.service.HelloServiceGrpc;
import com.xxx.tutorial.demo.service.impl.GreetingServiceImpl;

import io.grpc.Server;
import io.grpc.ServerBuilder;

public class HelloServer {

  private static final Logger logger = Logger.getLogger(HelloServer.class.getName());

  private static final int DEFAULT_PORT = 50051;

  private Server server = null;

  private void start() throws IOException {

    server = ServerBuilder.forPort(DEFAULT_PORT).addService(HelloServiceGrpc.bindService(new GreetingServiceImpl()))
        .build().start();

    logger.info("Server started, listening on " + DEFAULT_PORT);

    Runtime.getRuntime().addShutdownHook(new Thread() {
      @Override
      public void run() {
        System.err.println("*** shutting down gRPC server since JVM is shutting down");
        HelloServer.this.stop();
        System.err.println("*** server shut down");
      }
    });
  }

  private void stop() {
    if (server != null) {
      server.shutdown();
    }
  }

  /**
   * Await termination on the main thread since the grpc library uses daemon
   * threads.
   */
  private void blockUntilShutdown() throws InterruptedException {
    if (server != null) {
      server.awaitTermination();
    }
  }

  public static void main(String[] args) throws IOException, InterruptedException {
    final HelloServer server = new HelloServer();
    server.start();
    server.blockUntilShutdown();
  }

}

2.5 grpc-demo-client模块

  • 添加grpc-demo-interface依赖
代码语言:javascript
复制
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.xxx.tutorial</groupId>
    <artifactId>grpc-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>grpc-demo-service</artifactId>

  <dependencies>
    <dependency>
      <groupId>com.xxx.tutorial</groupId>
      <artifactId>grpc-demo-interface</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
  </dependencies>
</project>
  • 编写Client
代码语言:javascript
复制
package com.xxx.tutorial.demo.client;

import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import com.xxx.tutorial.demo.model.HelloRequest;
import com.xxx.tutorial.demo.model.HelloResponse;
import com.xxx.tutorial.demo.service.HelloServiceGrpc;

import io.grpc.ManagedChannel;
import io.grpc.netty.NegotiationType;
import io.grpc.netty.NettyChannelBuilder;

public class GreetingServiceClient {

  private static final Logger logger = Logger.getLogger(GreetingServiceClient.class.getName());

  private final ManagedChannel channel;

  private final HelloServiceGrpc.HelloServiceBlockingStub blockingStub;

  public GreetingServiceClient(String host, int port) {

    channel = NettyChannelBuilder.forAddress(host, port).negotiationType(NegotiationType.PLAINTEXT).build();
    blockingStub = HelloServiceGrpc.newBlockingStub(channel);
  }

  public void shutdown() throws InterruptedException {
    channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
  }

  public void sayHello(String name) {
    try {
      System.out.println("Will try to say Hello  " + name + " ...");
      HelloRequest request = HelloRequest.newBuilder().setName(name).setId(12345678).build();
      HelloResponse response = blockingStub.sayHello(request);
      System.out.println("result from server: " + response.getMessage());
    } catch (RuntimeException e) {
      System.out.println("RPC failed:" + e.getMessage());
      return;
    }
  }

  public static void main(String[] args) throws Exception {

    GreetingServiceClient client = new GreetingServiceClient("127.0.0.1", 50051);

    try {
      String name = "Eric";
      logger.info(String.format("Client 调用RPC接口,参数为name = {%s}", name));
      client.sayHello(name);
    } finally {
      client.shutdown();
    }
  }
}

至此,Maven工程中,4个模块的代码就简单写完了。接下来,测试一下。

三、测试

3.1 Server启动

直接运行HelloServer.java(其中包含main函数)即可。

3.2 Client运行

直接运行GreetingServiceClient.java(其中包含main函数)即可。

3.3 结果查看

我们可以看到,客户端调用接口,传值name为Eric,得到服务端的相应为Hello, Eric。

代码语言:javascript
复制
五月 26, 2017 6:41:20 下午 com.xxx.tutorial.demo.client.GreetingServiceClient main
信息: Client 调用RPC接口,参数为name = {Eric}
Will try to say Hello  Eric ...
result from server: Hello, Eric

再看一下,服务端的输出日志,也包含了请求参数,其中,id的值因为没有用到,所以在Service实现的sayHello接口,直接设置了12345678。

代码语言:javascript
复制
五月 26, 2017 6:40:14 下午 com.xxx.tutorial.demo.server.HelloServer start
信息: Server started, listening on 50051
五月 26, 2017 6:41:20 下午 com.xxx.tutorial.demo.service.impl.GreetingServiceImpl sayHello
信息: sayHello方法调用的请求参数信息: name={Eric}, id={12345678}

四、小结

从上面测试运行的结果可以看出,一个简单的grpc示例就完成了~

其中, grpc支持四种RPC类型

  • 简单RPC
  • 服务端流式RPC
  • 客户端流式RPC
  • 双向流式RPC

本示例完成的就是第一种“简单RPC”的方式,客户端发出单个请求,获得单个响应。后续会对其它几种RPC进行展示。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-09-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 孟君的编程札记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、根据proto自动生成代码
    • 1.1 定义服务接口
      • 1.2 产生proto文件对应代码
        • 1.3 生成rpc通信代码
        • 二、代码组成
          • 2.1 Maven工程结构
            • 2.2 grpc-demo-interface模块
              • 2.3 grpc-demo-service模块
                • 2.4 grpc-demo-server模块
                  • 2.5 grpc-demo-client模块
                  • 三、测试
                    • 3.1 Server启动
                      • 3.2 Client运行
                        • 3.3 结果查看
                        • 四、小结
                        相关产品与服务
                        云服务器
                        云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档