• gRPC 在 Python中的应用


    python -m grpc_tools.protoc --proto_path=. --python_out=. --grpc_python_out=. hello.proto

    简介

    在python中使用grpc和protobuf,比java和c#中使用要简单一些。只需要先安装grpcio包,然后就可以应用了。

    安装

    使用pip安装grpcio依赖包;

    $ pip install grpcio
    Collecting grpcio
    Downloading grpcio-1.7.0-cp27-cp27m-macosx_10_10_intel.whl (1.5MB)
    100% |████████████████████████████████| 1.5MB 18kB/s
    Requirement already satisfied: enum34>=1.0.4 in /Users/David/anaconda2/lib/python2.7/site-packages (from grpcio)
    Requirement already satisfied: futures>=2.2.0 in /Users/David/anaconda2/lib/python2.7/site-packages (from grpcio)
    Requirement already satisfied: six>=1.5.2 in /Users/David/anaconda2/lib/python2.7/site-packages (from grpcio)
    Collecting protobuf>=3.3.0 (from grpcio)
    Downloading protobuf-3.5.0-py2.py3-none-any.whl (388kB)
    100% |████████████████████████████████| 389kB 32kB/s
    Requirement already satisfied: setuptools in /Users/David/anaconda2/lib/python2.7/site-packages (from protobuf>=3.3.0->grpcio)
    Installing collected packages: protobuf, grpcio
    Successfully installed grpcio-1.7.0 protobuf-3.5.0

    安装时,自动地安装了protobuf工具包。

    定义protobuf

    下面定义一个简单的protobuf文件,在其中声明一个grpc服务。
    创建一个proto目录,并在其中创建grpchello.proto文件,如下内容。

    syntax = "proto3";
    package grpcDemo;

    message HelloRequest {
    string name = 1;
    }

    message HelloReply {
    string message = 1;
    }

    service gRPC {
    rpc SayHello (HelloRequest) returns (HelloReply) {}
    }

    Note:

    • 其实这个protobuf定义文件,在我们的java、c#版本示例中使用了,而且各版本的服务和客户端可以正常通行调用。

    编译protobuf

    使用protobuf的编译器,为我们生成python版本的Message定义和服务的架手脚。

    python -m grpc_tools.protoc -I./proto --python_out=. --grpc_python_out=. grpchello.proto
    1
    在当前目录下,生成2个文件:

    • grpchello_pb2.py
    • grpchello_pb2_grpc.py

    可以看看这2个文件:

    首先消息定义文件:

    Generated by the protocol buffer compiler. DO NOT EDIT!

    source: grpchello.proto

    import sys
    _b=sys.version_info[0]❤️ and (lambda x:x) or (lambda x:x.encode('latin1'))
    from google.protobuf import descriptor as _descriptor
    from google.protobuf import message as _message
    from google.protobuf import reflection as _reflection
    from google.protobuf import symbol_database as _symbol_database
    from google.protobuf import descriptor_pb2

    @@protoc_insertion_point(imports)

    _sym_db = _symbol_database.Default()

    DESCRIPTOR = _descriptor.FileDescriptor(
    name='grpchello.proto',
    package='grpcDemo',
    syntax='proto3',
    serialized_pb=_b(' x0fgrpchello.protox12x08grpcDemo"x1c x0cHelloRequestx12x0c x04namex18x01 x01( "x1d HelloReplyx12x0f x07messagex18x01 x01( 2B x04gRPCx12: x08SayHellox12x16.grpcDemo.HelloRequestx1ax14.grpcDemo.HelloReply"x00x62x06proto3')
    )

    _HELLOREQUEST = _descriptor.Descriptor(
    name='HelloRequest',
    full_name='grpcDemo.HelloRequest',
    filename=None,
    file=DESCRIPTOR,
    containing_type=None,
    fields=[
    _descriptor.FieldDescriptor(
    name='name', full_name='grpcDemo.HelloRequest.name', index=0,
    number=1, type=9, cpp_type=9, label=1,
    has_default_value=False, default_value=_b("").decode('utf-8'),
    message_type=None, enum_type=None, containing_type=None,
    is_extension=False, extension_scope=None,
    options=None),
    ],
    extensions=[
    ],
    nested_types=[],
    enum_types=[
    ],
    options=None,
    is_extendable=False,
    syntax='proto3',
    extension_ranges=[],
    oneofs=[
    ],
    serialized_start=29,
    serialized_end=57,
    )

    _HELLOREPLY = _descriptor.Descriptor(
    name='HelloReply',
    full_name='grpcDemo.HelloReply',
    filename=None,
    file=DESCRIPTOR,
    containing_type=None,
    fields=[
    _descriptor.FieldDescriptor(
    name='message', full_name='grpcDemo.HelloReply.message', index=0,
    number=1, type=9, cpp_type=9, label=1,
    has_default_value=False, default_value=_b("").decode('utf-8'),
    message_type=None, enum_type=None, containing_type=None,
    is_extension=False, extension_scope=None,
    options=None),
    ],
    extensions=[
    ],
    nested_types=[],
    enum_types=[
    ],
    options=None,
    is_extendable=False,
    syntax='proto3',
    extension_ranges=[],
    oneofs=[
    ],
    serialized_start=59,
    serialized_end=88,
    )

    DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST
    DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY
    _sym_db.RegisterFileDescriptor(DESCRIPTOR)

    HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), dict(
    DESCRIPTOR = _HELLOREQUEST,
    module = 'grpchello_pb2'

    @@protoc_insertion_point(class_scope:grpcDemo.HelloRequest)

    ))
    _sym_db.RegisterMessage(HelloRequest)

    HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), dict(
    DESCRIPTOR = _HELLOREPLY,
    module = 'grpchello_pb2'

    @@protoc_insertion_point(class_scope:grpcDemo.HelloReply)

    ))
    _sym_db.RegisterMessage(HelloReply)

    _GRPC = _descriptor.ServiceDescriptor(
    name='gRPC',
    full_name='grpcDemo.gRPC',
    file=DESCRIPTOR,
    index=0,
    options=None,
    serialized_start=90,
    serialized_end=156,
    methods=[
    _descriptor.MethodDescriptor(
    name='SayHello',
    full_name='grpcDemo.gRPC.SayHello',
    index=0,
    containing_service=None,
    input_type=_HELLOREQUEST,
    output_type=_HELLOREPLY,
    options=None,
    ),
    ])
    _sym_db.RegisterServiceDescriptor(_GRPC)

    DESCRIPTOR.services_by_name['gRPC'] = _GRPC

    @@protoc_insertion_point(module_scope)

    在看看grpc服务定义

    Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!

    import grpc

    import grpchello_pb2 as grpchello__pb2

    class gRPCStub(object):

    missing associated documentation comment in .proto file

    pass

    def init(self, channel):
    """Constructor.

    Args:
      channel: A grpc.Channel.
    """
    self.SayHello = channel.unary_unary(
        '/grpcDemo.gRPC/SayHello',
        request_serializer=grpchello__pb2.HelloRequest.SerializeToString,
        response_deserializer=grpchello__pb2.HelloReply.FromString,
        )
    

    class gRPCServicer(object):

    missing associated documentation comment in .proto file

    pass

    def SayHello(self, request, context):
    # missing associated documentation comment in .proto file
    pass
    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
    context.set_details('Method not implemented!')
    raise NotImplementedError('Method not implemented!')

    def add_gRPCServicer_to_server(servicer, server):
    rpc_method_handlers = {
    'SayHello': grpc.unary_unary_rpc_method_handler(
    servicer.SayHello,
    request_deserializer=grpchello__pb2.HelloRequest.FromString,
    response_serializer=grpchello__pb2.HelloReply.SerializeToString,
    ),
    }
    generic_handler = grpc.method_handlers_generic_handler(
    'grpcDemo.gRPC', rpc_method_handlers)
    server.add_generic_rpc_handlers((generic_handler,))

    简单看下:

    • 在grpc服务架手脚定义中,定义了gRPCStub,这是给client端使用,调用grpc服务的。
    • 定义的服务类gRPCServicer,方法SayHello需要我们在子类中进行实现。定义的add_gRPCServicer_to_server方法,用于把实现的类和grpc API调用注册起来。

    这里使用的几个主要方法(类):

    • grpc.server – Creates a Server with which RPCs can be serviced
    • grpc.method_handlers_generic_handler – Creates a GenericRpcHandler from RpcMethodHandlers.
    • grpc.unary_unary_rpc_method_handler – Creates an RpcMethodHandler for a unary-unary RPC method.

    实现服务

    在我们的实现服务的类中,使用服务方法,并在网络中暴露出来。

    -- coding: utf-8 --

    import grpc
    import time
    from concurrent import futures
    import grpchello_pb2, grpchello_pb2_grpc

    _HOST = 'localhost'
    _PORT = '8188'

    _ONE_DAY_IN_SECONDS = 60 * 60 * 24

    class gRPCServicerImpl(grpchello_pb2_grpc.gRPCServicer):

    def SayHello(self, request, context):
        print ("called with " + request.name)
        return grpchello_pb2.HelloReply(message='Hello, %s!' % request.name)
    

    def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    grpchello_pb2_grpc.add_gRPCServicer_to_server(gRPCServicerImpl(), server)
    server.add_insecure_port('[::]:'+_PORT)
    server.start()
    try:
    while True:
    time.sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
    server.stop(0)

    if name == 'main':
    serve()

    这里包括2个实现:

    • 1、在grpc的API的实现(服务实现类)gRPCServicerImpl中,实现SayHello方法。
    • 2、然后,定义网络服务和端口,把grpc的API注册到网络服务的处理上。这里简单利用了grpc.server类。

    使用客户端client

    在客户端,调用grpc的服务API。

    -- coding: utf-8 --

    """The Python implementation of the gRPC client."""
    from future import print_function
    import grpc
    from grpchello_pb2 import * ## or import grpchello_pb2
    from grpchello_pb2_grpc import *

    No grpcDemo! from grpcDemo import grpchello_pb2, grpchello_pb2_grpc #error!

    _PORT = '8188'

    def run():
    conn = grpc.insecure_channel(_HOST + ':' + _PORT)
    client = gRPCStub(channel=conn)
    response = client.SayHello(HelloRequest(name='David'))
    print("received: " + response.message)

    if name == 'main':

    if len(sys.argv)== 2:
        print (sys.argv[1])
        _HOST = sys.argv[1]
    else:
        _HOST = 'localhost'
    
    #    
    run()
    

    说明:

    • 1、 def insecure_channel(target, options=None):
      – Creates an insecure Channel to a server.
    • 2、 客户端使用服务的Stub,调用API。

    测试

    分别启动服务,然后再启动客户端,可以看到调用结果。
    也可以启动java、c#版本的grpc服务端、客户端,都能调用成功。

  • 相关阅读:
    .a包生成64位
    iOS教程
    iOS 难题解决日志------2层控制器 上面的控制器显示透明
    企业级的App发布流程
    如何从oc中去获取一个私有的变量.....
    iOS app的破解原理,就是去除已付费的账户信息的原理是什么?
    Could not launch "app_name"
    GCD时间轴
    Win8自动更新怎么关闭 取消Win8自动更新
    python3 elf文件解析
  • 原文地址:https://www.cnblogs.com/cosiray/p/9964340.html
Copyright © 2020-2023  润新知