gRPC相互通信实例

gRPC是一个高性能、开源和通用的RPC框架,面向移动和HTTP 2.0设计,目前支持C++、Go、Java、Python语言版本,目的是使得应用程序之间可以相互通信。接下来将通过Python和Java两种语言的简单实例分别来实现gRPC接口通信。

【Python】

1. 安装gRPC

pip install grpcio

2. 安装gRPC工具

pip install grpcio-tools

3. 通过protobuf定义接口和数据类型文件helloworld.proto

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

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

 4. 使用gRPC protobuf工具生成对应语言的库函数

python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. helloworld.proto

此时在该目录下生成两个文件helloworld_pb2.py和helloworld_pb2_grpc.py

5. 创建服务端代码hello_server.py

from concurrent import futures
import grpc
import helloworld_pb2
import helloworld_pb2_grpc

class Greeter(helloworld_pb2_grpc.GreeterServicer):
    def SayHello(self, request, context):
        return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()

if __name__ == '__main__':
    serve()

6. 创建客户端代码hello_client.py

from __future__ import print_function
import grpc
import helloworld_pb2
import helloworld_pb2_grpc

def run():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = helloworld_pb2_grpc.GreeterStub(channel)
        response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
    print("Greeter client received: " + response.message)

if __name__ == '__main__':
    run()

7. 先运行服务器,在运行客户端

python hello_server.py

python hello_client.py

 

【Java】

1. 用IDEA新建Maven项目grpc-helloworld, 目录结构如下

gRPC相互通信实例_第1张图片

2. 编写项目pom.xml文件如下



    4.0.0

    grpc
    grpc-helloworld
    1.0-SNAPSHOT

    
        
            com.google.guava
            guava
            23.6-jre
        
        
            org.apache.httpcomponents
            httpcore
            4.4.8
        
        
            com.google.protobuf
            protobuf-java
            3.5.1
        
        
            io.grpc
            grpc-all
            1.20.0
        
    

    
        
            
                kr.motd.maven
                os-maven-plugin
                1.4.1.Final
            
        
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
            
                org.xolstice.maven.plugins
                protobuf-maven-plugin
                0.6.1
                
                    com.google.protobuf:protoc:3.0.0:exe:${os.detected.classifier}
                    grpc-java
                    io.grpc:protoc-gen-grpc-java:0.15.0:exe:${os.detected.classifier}
                    /home/llh/modules/anaconda3/bin/protoc
                
                
                    
                        
                            compile
                            compile-custom
                        
                    
                
            
        
    

注意:是protoc编译工具所在的目录,修改成自己的

3. 编写helloworld.proto文件,和【Python】版本的第三步helloworld.proto保持一致不变

4.  编译.proto文件,分别执行compile和compile-custom

gRPC相互通信实例_第2张图片

执行完成后在target目录生成相应的库函数如下

gRPC相互通信实例_第3张图片

5. 创建服务端代码HelloWorldServer.java如下

package io.grpc.examples.helloworld;

import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
import java.util.logging.Logger;
/**
 * Server that manages startup/shutdown of a {@code Greeter} server.
 */
public class HelloWorldServer {
    private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName());

    private Server server;

    private void start() throws IOException {
        /* The port on which the server should run */
        int port = 50051;
        server = ServerBuilder.forPort(port)
                .addService(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 have 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");
            }
        });
    }

    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();
        }
    }
    //Main launches the server from the command line.
    public static void main(String[] args) throws IOException, InterruptedException {
        final HelloWorldServer server = new HelloWorldServer();
        server.start();
        server.blockUntilShutdown();
    }

    static class GreeterImpl extends GreeterGrpc.GreeterImplBase {
        @Override
        public void sayHello(HelloRequest req, StreamObserver responseObserver) {
            HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
        }
    }
}

6. 创建客户端代码HelloWorldClient.java如下

package io.grpc.examples.helloworld;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A simple client that requests a greeting from the {@link HelloWorldServer}.
 */
public class HelloWorldClient {
  private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName());

  private final ManagedChannel channel;
  private final GreeterGrpc.GreeterBlockingStub blockingStub;
  /** Construct client connecting to HelloWorld server at {@code host:port}. */
  public HelloWorldClient(String host, int port) {
    this(ManagedChannelBuilder.forAddress(host, port)
        // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
        // needing certificates.
        .usePlaintext()
        .build());
  }
  /** Construct client for accessing HelloWorld server using the existing channel. */
  HelloWorldClient(ManagedChannel channel) {
    this.channel = channel;
    blockingStub = GreeterGrpc.newBlockingStub(channel);
  }

  public void shutdown() throws InterruptedException {
    channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
  }
  /** Say hello to server. */
  public void greet(String name) {
    logger.info("Will try to greet " + name + " ...");
    HelloRequest request = HelloRequest.newBuilder().setName(name).build();
    HelloReply response;
    try {
      response = blockingStub.sayHello(request);
    } catch (StatusRuntimeException e) {
      logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
      return;
    }
    logger.info("Greeting: " + response.getMessage());
  }
  /**
   * Greet server. If provided, the first element of {@code args} is the name to use in the
   * greeting.
   */
  public static void main(String[] args) throws Exception {
    HelloWorldClient client = new HelloWorldClient("localhost", 50051);
    try {
      /* Access a service running on the local machine on port 50051 */
      String user = "world";
      if (args.length > 0) {
        user = args[0]; /* Use the arg as the name to greet if provided */
      }
      client.greet(user);
    } finally {
      client.shutdown();
    }
  }
}

7. 和上面一样,先启动服务器, 再运行客户端

最后最重要一点,不管用哪种语言编写,只要保持.proto文件完全一直(包括package),他们之前可以相互访问,例如本文章的【Python】grpc_client可以访问【Java】的grpc_server,【Java】的grpc_client可以访问【Python】的grpc_server。

 

参考资料:

grpc官网:https://grpc.io/

grpc-python的github: https://github.com/grpc/grpc/tree/master/examples/python

grpc-java的github: https://github.com/grpc/grpc-java/tree/master/examples/src/main/java/io/grpc/examples

你可能感兴趣的:(grpc)