1. 程式人生 > >使用gRPC搭建Server端與Client端

使用gRPC搭建Server端與Client端

reply imp aps 本地 .info exe block 目錄 處理

    gRPC簡介

  gRPC是一種RPC框架技術,采用Protocal Buffers(協議緩存) 作為其接口定義的語言(就是Proto來寫接口)和基礎的消息交換格式。

  在gRPC中,客戶端應用程序可以直接調用不同機器上的服務器應用程序上的方法,就像它是本地對象一樣,使您可以更輕松地創建分布式應用程序和服務。與許多RPC系統一樣,gRPC基於定義服務的思想,指定可以使用其參數和返回類型遠程調用的方法。在服務器端,服務器實現此接口並運行gRPC服務器來處理客戶端調用。在客戶端,客戶端有一個存根(Stub在某些語言中稱為客戶端),它提供與服務器相同的方法。

技術分享圖片

  gRPC客戶端和服務器可以在各種環境中相互運行和通信 - 從Google內部的服務器到您自己的桌面 - 並且可以使用任何gRPC支持的語言編寫。

因此,例如,您可以使用Go,Python或Ruby輕松創建Java中的gRPC服務器。此外,最新的Google API將具有gRPC版本的界面,讓您可以輕松地在應用程序中構建Google功能。

    使用協議緩存區(Protocal Buffers )

  

  正如您將在我們的示例中更詳細地看到的那樣,您可以在普通的proto文件中定義gRPC服務,並將RPC方法參數和返回類型指定為協議緩沖區消息:

  

// 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; }

  這裏我們將采用protoc特殊的gRPC插件從proto文件生成代碼。但是,使用gRPC插件,您可以生成gRPC客戶端和服務器代碼,十分方便

    搭建項目

  maven配置文件:

  

  1 <properties>
  2
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 3 <grpc.version>1.13.1</grpc.version><!-- CURRENT_GRPC_VERSION --> 4 <protobuf.version>3.5.1</protobuf.version> 5 <protoc.version>3.5.1-1</protoc.version> 6 <netty.tcnative.version>2.0.7.Final</netty.tcnative.version> 7 </properties> 8 <dependencies> 9 <dependency> 10 <groupId>io.dropwizard.metrics</groupId> 11 <artifactId>metrics-core</artifactId> 12 <version>4.0.0</version> 13 </dependency> 14 <dependency> 15 <groupId>io.grpc</groupId> 16 <artifactId>grpc-netty</artifactId> 17 <version>${grpc.version}</version> 18 </dependency> 19 <dependency> 20 <groupId>io.grpc</groupId> 21 <artifactId>grpc-protobuf</artifactId> 22 <version>${grpc.version}</version> 23 </dependency> 24 <dependency> 25 <groupId>io.grpc</groupId> 26 <artifactId>grpc-stub</artifactId> 27 <version>${grpc.version}</version> 28 </dependency> 29 <dependency> 30 <groupId>io.grpc</groupId> 31 <artifactId>grpc-alts</artifactId> 32 <version>${grpc.version}</version> 33 </dependency> 34 <dependency> 35 <groupId>io.grpc</groupId> 36 <artifactId>grpc-testing</artifactId> 37 <version>${grpc.version}</version> 38 <scope>test</scope> 39 </dependency> 40 <dependency> 41 <groupId>io.netty</groupId> 42 <artifactId>netty-tcnative-boringssl-static</artifactId> 43 <version>${netty.tcnative.version}</version> 44 </dependency> 45 <dependency> 46 <groupId>com.google.api.grpc</groupId> 47 <artifactId>proto-google-common-protos</artifactId> 48 <version>1.0.0</version> 49 </dependency> 50 <dependency> 51 <groupId>com.google.protobuf</groupId> 52 <artifactId>protobuf-java-util</artifactId> 53 <version>${protobuf.version}</version> 54 </dependency> 55 <dependency> 56 <groupId>junit</groupId> 57 <artifactId>junit</artifactId> 58 <version>4.12</version> 59 <scope>test</scope> 60 </dependency> 61 <dependency> 62 <groupId>org.mockito</groupId> 63 <artifactId>mockito-core</artifactId> 64 <version>1.9.5</version> 65 <scope>test</scope> 66 </dependency> 67 <dependency> 68 <groupId>junit</groupId> 69 <artifactId>junit</artifactId> 70 <version>4.12</version> 71 </dependency> 72 </dependencies> 73 <build> 74 <extensions> 75 <extension> 76 <groupId>kr.motd.maven</groupId> 77 <artifactId>os-maven-plugin</artifactId> 78 <version>1.5.0.Final</version> 79 </extension> 80 </extensions> 81 <plugins> 82 <plugin> 83 <groupId>org.xolstice.maven.plugins</groupId> 84 <artifactId>protobuf-maven-plugin</artifactId> 85 <version>0.5.1</version> 86 <configuration> 87 <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact> 88 <pluginId>grpc-protocol-buffers</pluginId> 89 <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> 90 <!-- 使用自己從官網下的protoc --> 91 <!--<protocExecutable>C:/Users/14687/workspace/google/protoc-3.6.0-win32/bin</protocExecutable>--> 92 </configuration> 93 <executions> 94 <execution> 95 <goals> 96 <goal>compile</goal> 97 <goal>compile-custom</goal> 98 </goals> 99 </execution> 100 </executions> 101 </plugin> 102 <plugin> 103 <groupId>org.apache.maven.plugins</groupId> 104 <artifactId>maven-enforcer-plugin</artifactId> 105 <version>1.4.1</version> 106 <executions> 107 <execution> 108 <id>enforce</id> 109 <goals> 110 <goal>enforce</goal> 111 </goals> 112 <configuration> 113 <rules> 114 <requireUpperBoundDeps/> 115 </rules> 116 </configuration> 117 </execution> 118 </executions> 119 </plugin> 120 <plugin> 121 <groupId>org.apache.maven.plugins</groupId> 122 <artifactId>maven-compiler-plugin</artifactId> 123 <configuration> 124 <source>1.8</source> 125 <target>1.8</target> 126 </configuration> 127 </plugin> 128 </plugins> 129 </build>
  註意:這裏的 protoc.version 和 protobuf.version 需要保持一致

    編寫.proto文件

  在 java 目錄下,新建proto文件,在裏面寫.proto文件,如下:

  

syntax = "proto3";
option java_package = "com.example.service";
package helloword;
// the greeter service definition
service Greeter {
    //send a greeting
    rpc SayHello (HelloRequest) returns (HelloReply) {
    }
}
message HelloRequest {
    string name = 1;
}
message HelloReply {
    string message = 1;
}

  提示:用IDEA可以安裝相應插件:Protobuf Support(File-->setting-->Plugins-->Browse repositories)

    編寫server端

技術分享圖片
 1 public class HelloWorldServer {
 2     private static final Logger log = Logger.getLogger(HelloWorldServer.class.getName());
 3 
 4     private Server server;
 5 
 6     public static void main(String[] args) throws IOException, InterruptedException {
 7         final HelloWorldServer server = new HelloWorldServer();
 8         server.start();
 9         server.blockUntilShutdown();
10     }
11 
12     private void start() throws IOException {
13         int port = 50051;
14         //1.forPort 指定監聽客戶端請求的端口
15         //2.創建我們的服務端實現類的實例GreeterImpl並將傳遞給構建器的addService方法
16         //3.調用build ()並 start()在構建器上為我們的服務創建和啟動RPC服務器
17         server = ServerBuilder.forPort(port)
18                 .addService(new GreeterImpl())
19                 .build()
20                 .start();
21         log.info("Server stated , listener on port:" + port);
22         //JVM關閉時調用的鉤子
23         Runtime.getRuntime().addShutdownHook(new Thread() {
24             @Override
25             public synchronized void start() {
26                 System.err.println("*** shutting down gRPC server since JVM is shutting down");
27                 HelloWorldServer.this.stop();
28                 System.err.println("*** server shut down");
29             }
30         });
31     }
32 
33     private void stop() {
34         if (null != server) {
35             server.shutdown();
36         }
37     }
38 
39     /**
40      * Await termination on the main thread since the grpc library uses daemon threads.
41      *
42      * @throws InterruptedException
43      */
44     private void blockUntilShutdown() throws InterruptedException {
45         if (null != server) {
46             server.awaitTermination();
47         }
48     }
49 
50     private class GreeterImpl extends GreeterGrpc.GreeterImplBase {
51         /**
52          * @param request          請求
53          * @param responseObserver 響應觀察器
54          */
55         @Override
56         public void sayHello(HelloRequest request,
57                              StreamObserver<HelloReply> responseObserver) {
58             HelloReply reply = HelloReply.newBuilder()
59                     .setMessage("Hello" + request.getName())
60                     .build();
61             //返回 reply數據
62             responseObserver.onNext(reply);
63             //指定完成gRPC的處理
64             responseObserver.onCompleted();
65         }
66     }
67 }
View Code

    編寫client端

技術分享圖片
public class HelloWordClient {
    private static final Logger log = Logger.getLogger(HelloWordClient.class.getName());
    private final ManagedChannel channel;
    //阻塞/同步 的stub(存根)
    private final GreeterGrpc.GreeterBlockingStub blockingStub;
    //非阻塞/異步 的stub
    private final GreeterGrpc.GreeterStub async;

    /**
     * Greet server. If provided, the first element of {@code args} is the name to use in the
     * greeting.
     */
    public static void main(String[] args) {
        HelloWordClient client = new HelloWordClient("localhost", 50051);
        String user = "world";
        try {
            client.greet(user);
            client.shutdown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public HelloWordClient(String host, int port) {
        this(ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext()
                .build());
    }

    public HelloWordClient(ManagedChannel channel) {
        this.channel = channel;

        blockingStub = GreeterGrpc.newBlockingStub(channel);
        async = GreeterGrpc.newStub(channel);
    }

    public void greet(String name) {
        log.info("Will try to greet" + name + "..");
        HelloRequest request = HelloRequest.newBuilder().setName(name).build();
        HelloReply response = null;
        try {
            //使用阻塞 stub調用
            response = blockingStub.sayHello(request);
        } catch (StatusRuntimeException e) {
            log.info(String.format("rpc failed:%s", e.getStatus()));
        }
        log.info("Greeting: " + response.getMessage());
    }

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

gRPC官網

GitHub倉庫地址

使用gRPC搭建Server端與Client端