zoukankan      html  css  js  c++  java
  • 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服务端、客户端,都能调用成功。

  • 相关阅读:
    Poj 2017 Speed Limit(水题)
    Poj 1316 Self Numbers(水题)
    Poj 1017 Packets(贪心策略)
    Poj 1017 Packets(贪心策略)
    Poj 2662,2909 Goldbach's Conjecture (素数判定)
    Poj 2662,2909 Goldbach's Conjecture (素数判定)
    poj 2388 Who's in the Middle(快速排序求中位数)
    poj 2388 Who's in the Middle(快速排序求中位数)
    poj 2000 Gold Coins(水题)
    poj 2000 Gold Coins(水题)
  • 原文地址:https://www.cnblogs.com/cosiray/p/9964340.html
Copyright © 2011-2022 走看看