gRPC python 和Java实现

简介

gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.

gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

gRPC 是什么?

在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。

å¾1

gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制。

编写proto文件

我们使用 protocol buffers 接口定义语言来定义服务方法,用 protocol buffer 来定义参数和返回类型。客户端和服务端均使用服务定义生成的接口代码。

我们来实现一个sayHello方法,这里采用官网提供的proto文件,新建一个helloworld.protoGreeter 服务有一个方法 SayHello ,可以让服务端从远程客户端接收一个包含用户名的 HelloRequest 消息后,在一个 HelloReply 里发送回一个 Greeter

syntax = "proto3";

option java_package = "com.grpc.test";

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

服务到这定义好了,现在开始配置环境。

安装

一、java安装

参照https://github.com/grpc/grpc-java 步骤进行安装

创建Maven 项目

修改pom.xml,引入依赖 和插件。

<?xml version="1.0" encoding="UTF-8"?>
<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.demo</groupId>
    <artifactId>GrpcTest</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty-shaded</artifactId>
            <version>1.16.1</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>1.16.1</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.16.1</version>
        </dependency>
    </dependencies>
    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.5.0.Final</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.5.1</version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.16.1:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

二、python安装

python安装相对简单。安装以下三个依赖包

1)gRPC 的安装,执行命令:pip install grpcio

2)ProtoBuf 相关的 python 依赖库,执行:pip install protobuf

3)安装 python grpc 的 protobuf 编译工具,执行:pip install grpcio-tools

撸代码

安装成功后开始撸代码首先从java开始

一、java客户端、服务端

首先需要把之前创建的helloworld.proto放到项目里,不能随便放,有默认位置,在src/main/下新建proto文件夹,并把helloworld.proto放进去。

在控制台输入 mvn compile。会在target下生产一堆文件,在target/generated-sources/protobuf/java 和grpc-java下会生成我们需要的文件

接下来开始写代码,首先创建一个服务端处理消息的类,实现我们服务定义的生成的服务接口,做我们的服务的实际的“工作”。

package com.grpc.test;

import io.grpc.stub.StreamObserver;

/**
 * @author luoaojin
 * @CreateTime 2018-11-14
 * @Description
 */
public class SayHelloImpl extends GreeterGrpc.GreeterImplBase {
    @Override
    public void sayHello(Helloworld.HelloRequest request, StreamObserver<Helloworld.HelloReply> responseObserver) {
//     这一行一定要删除,否则会提示你没有实现这个方法。
//        super.sayHello(request, responseObserver);
        System.out.println(request.getName());

        Helloworld.HelloReply data = Helloworld.HelloReply.newBuilder().setMessage("Hello " + request.getName()).build();

        responseObserver.onNext(data);
        responseObserver.onCompleted();
    }

}

编写服务端

​
package com.grpc.test;

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


import java.io.IOException;

/**
 * @author luoaojin
 * @CreateTime 2018-11-14
 * @Description
 */
public class DefinedServer {

    private Server server;

    private void start() throws IOException {
        server = ServerBuilder.forPort(50051)//服务端只用指定端口号
                .addService(new SayHelloImpl())
                .build()
                .start();

        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");
                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 DefinedServer server = new DefinedServer();
        server.start();
        server.blockUntilShutdown();
    }


}

​

编写客户端:

package com.grpc.test;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;

import java.util.concurrent.TimeUnit;

/**
 * @author luoaojin
 * @CreateTime 2018-11-14
 * @Description
 */
public class Client {

    private final ManagedChannel channel;
    private final GreeterGrpc.GreeterBlockingStub blockingStub;

    /**
     * Construct client connecting to HelloWorld server at {@code host:port}.
     */
    public Client(String host, int port) {

        channel = ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext()
                .build();
        blockingStub = GreeterGrpc.newBlockingStub(channel);
    }

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

    /**
     * Say hello to server.
     */
    public void greet(String name) {

        Helloworld.HelloRequest request = Helloworld.HelloRequest.newBuilder().setName(name).build();
        Helloworld.HelloReply response;
        try {
            response = blockingStub.sayHello(request);
        } catch (StatusRuntimeException e) {
            System.out.println("RPC failed: {0}"+ e.getStatus());
            return;
        }
        System.out.println(("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 {
        Client client = new Client("localhost", 50051);
        try {

            String user = "luo";
            if (args.length > 0) {
                user = args[0];
            }
            client.greet(user);
        } finally {
            client.shutdown();
        }
    }

}

逻辑比较简单,主要就是把名称给服务端发送过去。

这样简单的demo就完成了,那我们先启动服务端,再起客户端。见到下图结果。大功告成。

二、python服务端,客户端

同样,我们也需要实现服务端和客户端,那我们也采用同一个proto文件,因为未来要实现python 和java互相通信,所以必须要用同一套接口。

在python 项目文件夹下,将proto文件贴过来。

需要编译的helloworld.proto 文件存放在 . 目录下,生成的文件放在.下,则可以使用命令:

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

然后项目会出现生成两个文件,由于对python不太熟悉,所以就简单叙述叙述怎么使用。

helloworld_pb2.py: 用来和 protobuf 数据进行交互

helloworld_pb2_grpc.py: 用来和 grpc 进行交互

接着开启编写我们的服务端。 依赖于我们生成的两个文件。

import time
from concurrent import futures

import grpc

import helloworld_pb2
import helloworld_pb2_grpc

_ONE_DAY_IN_SERVICE = 60 * 60 * 24
IP = "[::]:50051"

class service(helloworld_pb2_grpc.GreeterServicer):

    def SayHello(self, request, context):
        txt = request.name
        return helloworld_pb2.HelloReply(message ='hello {msg}'.format(msg = txt))



def serve():
    grpcServer = grpc.server(futures.ThreadPoolExecutor(max_workers=4))
    helloworld_pb2_grpc.add_GreeterServicer_to_server(service(), grpcServer)
    grpcServer.add_insecure_port(IP)
    grpcServer.start()
    print("server start success")

    try:
        while True:
            time.sleep(_ONE_DAY_IN_SERVICE)
    except KeyboardInterrupt:
        grpcServer.stop(0)


if __name__ == '__main__':

    serve()

接着是客户端

import grpc
import helloworld_pb2
import helloworld_pb2_grpc

IP = 'localhost:50051'
def run():
    channel = grpc.insecure_channel(IP)
    stub = helloworld_pb2_grpc.GreeterStub(channel=channel)
    response = stub.SayHello(helloworld_pb2.HelloRequest(name='luo'))
    print("recevied: " + response.message)

if __name__ == '__main__':
    run()

创建完毕后项目的结构是这样的

整体逻辑跟java差不多。同样是先启动服务端,再启动客户端,出现下面界面,大功告成。

三、java 和python 互相通信,实力扣题

启动java 或python服务端,然后再启动不同语言的服务端,这样可以测试通过。

 

 

四、感谢

第一次写博客,有问题欢迎斧正。同时也感谢参考的大神的文章。

grpc官网 :http://doc.oschina.net/grpc?t=60134

https://blog.csdn.net/u010626747/article/details/80824582

https://www.colabug.com/2904867.html

https://blog.csdn.net/lluozh2015/article/details/53106475

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值