下面我们使用 必威:gRPC,初步尝试是在python脚本

https://grpc.io/docs/tutorials/basic/python.html

安装:

  1. gRPC 的安装:

$ pip install grpcio

  1. 安装 ProtoBuf 相关的 python 依赖库:

$ pip install protobuf

  1. 安装 python grpc 的 protobuf 编译工具:

$ pip install grpcio-tools

python -m grpc_tools.protoc -I./protos --python_out=. --grpc_python_out=. ./protos/xxx.proto

使用

  1. 创建 demo python 工程
![](https://upload-images.jianshu.io/upload_images/208550-efc7e919daa289de.png)

Paste_Image.png
  1. 在 example 包中编写 person.proto

    syntax = "proto3";
    package example;
    
    message person {   
        int32 id = 1;
        string name = 2;
    }
    
    message all_person {    
        repeated person Per = 1;
    }
    
  2. 进入 demo 工程的 example 目录,使用 protoc 编译 person.proto

$ protoc --python_out=. person.proto
就会生成 person_pb2.py 文件

  1. 在 python 工程中使用 protobuf 进行序列化与反序列化
    main.py:

    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    from example import person_pb2
    
    # 为 all_person 填充数据
    pers = person_pb2.all_person()
    p1 = pers.Per.add()
    p1.id = 1
    p1.name = 'xieyanke'
    p2 = pers.Per.add()
    p2.id = 2
    p2.name = 'pythoner'
    
    # 对数据进行序列化
    data = pers.SerializeToString()
    
    # 对已经序列化的数据进行反序列化
    target = person_pb2.all_person()
    target.ParseFromString(data)
    print(target.Per[1].name)  #  打印第一个 person name 的值进行反序列化验证
    

  • 交流可以加 QQ 群:397234385
  • 或者 QQ 扫码入群:

必威 1

qq群.jpg

grpc-java 初探

 

gRPC 简介:

gRPC 是一款高性能、开源的 RPC 框架,产自 Google,基于 ProtoBuf 序列化协议进行开发,支持多种语言(Golang、Python、Java等),本篇只介绍 Python 的 gRPC 使用。因为 gRPC 对 HTTP/2 协议的支持使其在 Android、IOS 等客户端后端服务的开发领域具有良好的前景。gRPC 提供了一种简单的方法来定义服务,同时客户端可以充分利用 HTTP/2 stream 的特性,从而有助于节省带宽、降低 TCP 的连接次数、节省CPU的使用等。

初步尝试是在python脚本中与java对接接口,经常官方文档的一顿学习,成功调通了接口

安装:

  1. 安装 protoc :Protoc下载地址,可以根据自己的系统下载相应的 protoc,windows 用户统一下载 win32 版本。
  2. 配置 protoc 到系统的环境变量中,执行如下命令查看是否安装成功:

$ protoc --version
如果正常打印 libprotoc 的版本信息就表明 protoc 安装成功

  1. 安装 ProtoBuf 相关的 python 依赖库

$ pip install protobuf

编写客户端文件

为了调用服务端的方法,首先需要创建一个或两个stub:
阻塞式stub:rpc调用会阻塞等待服务端响应后返回消息或异常信息
非阻塞式stub:非阻塞调用方式,响应异步返回

package com.weibo.dorteam.grpc;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
import io.grpc.examples.helloworld.GreeterGrpc;
import io.grpc.examples.helloworld.HelloReply;
import io.grpc.examples.helloworld.HelloRequest;

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

public class helloClient {


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

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

    /** Construct client connecting to HelloWorld server at {@code host:port}. */
    // 首先,我们需要为stub创建一个grpc的channel,指定我们连接服务端的地址和端口
    // 使用ManagedChannelBuilder方法来创建channel
    public helloClient(String host, int port) {
        channel = ManagedChannelBuilder.forAddress(host, port)
        // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
        // needing certificates.
        .usePlaintext(true)
        .build();
        // 使用我们从proto文件生成的GreeterGrpc类提供的newBlockingStub方法指定channel创建stubs
        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 + " ...");
        // 创建并定制protocol buffer对象,使用该对象调用服务端的sayHello方法,获得response
        HelloRequest request = HelloRequest.newBuilder().setName(name).build();
        HelloReply response;
        try {
            response = blockingStub.sayHello(request);
        // 如果有异常发生,则异常被编码成Status,可以从StatusRuntimeException异常中捕获
        } 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 {
        helloClient client = new helloClient("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();
        }
    }
}

需要安装的python包如下:

实践:

下面我们使用 gRPC 定义一个接口,该接口实现对传入的数据进行大写的格式化处理。

  • 创建项目 python demo 工程:
![](https://upload-images.jianshu.io/upload_images/208550-bd34d08e0c12cdeb.png)

Paste_Image.png
  1. client目录下的 main.py 实现了客户端用于发送数据并打印接收到 server 端处理后的数据
  1. server 目录下的 main.py 实现了 server 端用于接收客户端发送的数据,并对数据进行大写处理后返回给客户端
  2. example 包用于编写 proto 文件并生成 data 接口
  • 定义 gRPC 接口:
syntax = "proto3";
package example;
service FormatData {
  rpc DoFormat(Data) returns (Data){}
}
message Data {
  string text = 1;
}
  • 编译 protobuf:

$ python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./data.proto #在 example 目录中执行编译,会生成:data_pb2.py 与 data_pb2_grpc.py

  • 实现 server 端:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import grpc
import time
from concurrent import futures
from example import data_pb2, data_pb2_grpc

_ONE_DAY_IN_SECONDS = 60 * 60 * 24
_HOST = 'localhost'
_PORT = '8080'

class FormatData(data_pb2_grpc.FormatDataServicer):
    def DoFormat(self, request, context):
        str = request.text
        return data_pb2.Data(text=str.upper())

def serve():
    grpcServer = grpc.server(futures.ThreadPoolExecutor(max_workers=4))
    data_pb2_grpc.add_FormatDataServicer_to_server(FormatData(), grpcServer)
    grpcServer.add_insecure_port(_HOST + ':' + _PORT)
    grpcServer.start()
    try:
        while True:
            time.sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
        grpcServer.stop(0)

if __name__ == '__main__':
    serve()
  • 实现 client 端:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import grpc
from example import data_pb2, data_pb2_grpc

_HOST = 'localhost'
_PORT = '8080'

def run():
    conn = grpc.insecure_channel(_HOST + ':' + _PORT)
    client = data_pb2_grpc.FormatDataStub(channel=conn)
    response = client.DoFormat(data_pb2.Data(text='hello,world!'))
    print("received: " + response.text)

if __name__ == '__main__':
    run()
  • 执行验证结果:
  1. 先启动 server,之后再执行 client
  1. client 侧控制台如果打印的结果为:“received: HELLO,WORLD!” ,证明 gRPC 接口定义成功

  • 交流可以加 QQ 群:397234385
  • 或者 QQ 扫码入群:

必威 2

qq群.jpg

这里解释一下,python(不解释) -m(也不解释) grpc_tools.protoc(上面安装的三方)
-I./protos(标识当前目录下的protos文件夹,xxx.proto需要在这个文件夹中) --python_out=.(当前目录生成输出文件) --grpc_python_out=.(当前目录生成grpc文件) ./protos/xxx.proto(xxx.proto的相对路径)

ProtoBuf: 是一套完整的 IDL(接口描述语言),出自Google,基于 C++ 进行的实现,开发人员可以根据 ProtoBuf 的语言规范生成多种编程语言(Golang、Python、Java 等)的接口代码,本篇只讲述 Python 的基础操作。据说 ProtoBuf 所生成的二进制文件在存储效率上比 XML 高 3~10 倍,并且处理性能高 1~2 个数量级,这也是选择 ProtoBuf 作为序列化方案的一个重要因素之一。

mvn编译运行

服务端运行:

#  不需要参数
mvn exec:java -Dexec.mainClass="com.weibo.dorteam.grpc.helloServer"

# 需要参数
mvn exec:java -Dexec.mainClass="com.weibo.dorteam.grpc.helloServer" -Dexec.args="arg0 arg1 arg2"

# 传递classpath
mvn exec:java -Dexec.mainClass="com.weibo.dorteam.grpc.helloServer" -Dexec.classpathScope=runtime

客户端运行:

mvn exec:java -Dexec.mainClass="com.weibo.dorteam.grpc.helloClient"

 

解决方法就是在greeter_server.py中(这个文件不知道请看上面的链接)加载django,大致如下:

使用python的client端去访问java的server端

docker run -i -t -v /data0/liuyu9/test/grpc/python-grpc:/python-grpc grpc/python python /python-grpc/helloClient.py
输出结果为:hello you

若不适用grpc/python的镜像,物理机的python需要安装grpc,安装过程中,版本及各种依赖包的冲突非常麻烦。。。没有耐心了


# -*- coding: utf-8 -*-
import grpc
import data_pb2,data_pb2_grpc

_HOST = 'localhost'
_PORT = '8080'

def run():
    conn = grpc.insecure_channel(_HOST + ':' + _PORT)
    client = data_pb2_grpc.gRPCStub(channel=conn)
    response = client.SayHello(data_pb2.HelloRequest(name='hello,world!'))
    print("received: " + response.text)

if __name__ == '__main__':
    run()

https://grpc.io/docs/quickstart/python.html
不过在教程里clone的那个项目实在是大,不确定哪些是需要的,经过测试后给出需要的:

使用protoc命令行生成类文件

pip install googleapis-common-protos


编译 protoc-gen-grpc-java插件

下载grpc-java后,执行一下命令

cd grpc-java/compile
# 编译插件
../gradlew java_pluginExecutable
# 测试插件
../gradlew test

若看到BUILD SUCCESSFUL字样,则编译成功

python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. data.proto

我既想用django的model又想用grpc该怎么办呢,django是一个服务,grpc是一个服务,直接暴力把grpc代码加入django是没办法使用models和views的。

编写服务端文件

编写服务端文件的工作有两部分:

  1. 重写proto文件定义的服务生成的服务基类,确定服务的工作内容
  2. 运行grpc服务,监听客户端请求并做出响应

    package com.weibo.dorteam.grpc;

    import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.stub.StreamObserver;

    import io.grpc.examples.helloworld.GreeterGrpc; import io.grpc.examples.helloworld.HelloReply; import io.grpc.examples.helloworld.HelloRequest;

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

    public class helloServer {

     private static final Logger logger = Logger.getLogger(helloServer.class.getName());
     private int port = 50051;
     private Server server;
    
     private void start() throws IOException {
       // 使用ServerBuilder来构建和启动服务,通过使用forPort方法来指定监听的地址和端口
       // 创建一个实现方法的服务GreeterImpl的实例,并通过addService方法将该实例纳入
       // 调用build() start()方法构建和启动rpcserver
       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");
               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();
           }
         }
    
         /**
          * Main launches the server from the command line.
          */
         public static void main(String[] args) throws IOException, InterruptedException {
           final helloServer server = new helloServer();
           server.start();
           server.blockUntilShutdown();
         }
    
     // 我们的服务GreeterImpl继承了生成抽象类GreeterGrpc.GreeterImplBase,实现了服务的所有方法
     private class GreeterImpl extends GreeterGrpc.GreeterImplBase {
    
         @Override
         public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
           HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
           // 使用响应监视器的onNext方法返回HelloReply
           responseObserver.onNext(reply);
           // 使用onCompleted方法指定本次调用已经完成
           responseObserver.onCompleted();
         }
       }
    

    }

消息类型,StreamObserver一个响应监视器,是服务器调生成响应结果使用的特定接口

 

运行时只需要运行该脚本即可,django服务不必启用

编辑服务端文件

同上

本文由必威发布于必威-编程,转载请注明出处:下面我们使用 必威:gRPC,初步尝试是在python脚本

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。