一个简单的python gRpc (route_guide_simple)

route_guide_simple

这是一个简化版的route_guide,本文参考自gRpc官方文档,略有删改,水平有限翻译不对的地方敬请见谅。

完整代码地址

# 生成_pb2.py和_pb2_grpc.py文件
python -m grpc_tools.protoc -I ./ --python_out . --grpc_python_out . ./route_guide.proto

文件结构以及说明

./
├── README.md
├── route_guide_client.py  # 客户端
├── route_guide_db.json  # 提供数据
├── route_guide_pb2_grpc.py  # 生成的
├── route_guide_pb2.py  # 生成的
├── route_guide.proto  # protocol buffer file
├── route_guide_resources.py  # 提供数据
└── route_guide_server.py  # 服务端
  • route_guide_client.pyroute_guide_server.py文件分别为客户端和服务端,它们的通信是通过gRpc实现的。
  • route_guide_db.jsonroute_guide_resources.py文件是提供数据的。
  • route_guide.proto文件是protocal buffer file,protobuf是一种接口描述语言(IDL),里面定义了语言无关的数据结构以供其他语言调用。
  • route_guide_pb2.pyroute_guide_pb2_grpc.py是通过protobuf生成的
    • route_guide_pb2定义了messages的数据结构
    • route_guide_pb2_grpc
      • 客户端可以通过RouteGuideStub调用RouteGuideRPC
      • RouteGuideServicer定义了RouteGuide服务的实现接口
      • add_RouteGuideServicer_to_serverRouteGuideServicer添加到grpc.Server

代码说明

创建服务器

实现 RouteGuide :

gRpc/examples/route_guide_simple/route_guide_server.py 模块中有一个 RouteGuideServicer 类,它继承自 route_guide_pb2_grpc. RouteGuideServicer ,并实现了所有 RouteGuide 方法。

# RouteGuideServicer provides an implementation of the methods of the RouteGuide service.
class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):

Simple RPC

GetFeature是一个最简单的类型,它仅从客户端获取Point,然后在Feature中返回数据库中相应的feature信息。

def GetFeature(self, request, context):
    feature = get_feature(self.db, request)
    if feature is None:
        return route_guide_pb2.Feature(name="", location=request)
    else:
        return feature

该方法传递了 route_guide_pb2. Point 请求给RPC,以及一个 grpc. ServicerContext 对象,它提供了RPC特定信息(例如超时限制)。返回一个 route_guide_pb2. Feature 响应。

gRpc服务器

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    route_guide_pb2_grpc.add_RouteGuideServicer_to_server(
        RouteGuideServicer(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()

serverstart() 方法是非阻塞的。将实例化一个新线程来处理请求。在此期间,调用 server.start() 的线程通常不会执行任何其他工作。

在这种情况下,您可以调用 server.wait_for_termination() 来彻底清除调用线程,直到服务器终止。

创建客户端

route_guide_client

创建存根

调用服务方法之前,我们要先创建一个存根。

grpc.insecure_channel('localhost:50051')
stub = route_guide_pb2_grpc.RouteGuideStub(channel)

我们实例化一个 route_guide_pb2_grpc 模块的 RouteGuideStub 类,它是由 protobuf 文件生成的。

调用服务方法

同步:对于返回单一响应的RPC方法 ("response-unary" methods) ,gRPC Python支持同步(阻塞)和异步(非阻塞)控制流语义。同步调用简单的RPC方法 GetFeature 几乎与调用本地方法一样直接。 RPC调用等待服务器响应,并且将返回响应或引发异常:

feature = stub.GetFeature(point)

异步:对于 GetFeature 的异步调用与此类似,就像在线程池中异步调用本地方法一样:

feature_future = stub.GetFeature.future(point)
feature = feature_future.result()

启动服务

# 启动服务端
python route_guide_server.py
# 启动客户端
python route_guide_client.py

客户端打印结果:

-------------- GetFeature --------------
Feature called Berkshire Valley Management Area Trail, Jefferson, NJ, USA at latitude: 409146138
longitude: -746188906

Found no feature at 

protoc生成的代码

gRpc Python 依赖于协议缓冲编译器(protoc)来生成代码。它使用插件通过 gRPC-specific 代码通过 plain protoc 来补充所生成的代码。对于包含gRPC服务的.proto服务描述, plain protoc 生成的代码在_pb2.py文件中合成,而 gRPC-specific 代码在_pb2_grpc.py文件中。后者的 python 模块导入前者。

示例

syntax = "proto3";
package route_guide_simple;

// the route guide service
service RouteGuide{
    // A simple RPC 
    rpc GetFeature (Point) returns (Feature) {}
}

message Point{
    int32 latitude = 1;
    int32 longitude = 2;
}

message Feature{
    string name = 1;
    Point location = 2;
}

当服务被编译时,gRPC 的protoc 插件会生成类似于下面的 _pb2_grpc.py 文件的代码:

# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
"""Client and server classes corresponding to protobuf-defined services."""
import grpc

import route_guide_pb2 as route__guide__pb2

class RouteGuideStub(object):
    """the route guide service
    """

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

        Args:
            channel: A grpc.Channel.
        """
        self.GetFeature = channel.unary_unary(
                '/route_guide_simple.RouteGuide/GetFeature',
                request_serializer=route__guide__pb2.Point.SerializeToString,
                response_deserializer=route__guide__pb2.Feature.FromString,
                )

class RouteGuideServicer(object):
    """the route guide service
    """

    def GetFeature(self, request, context):
        """A simple RPC 
        """
        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
        context.set_details('Method not implemented!')
        raise NotImplementedError('Method not implemented!')

def add_RouteGuideServicer_to_server(servicer, server):
    rpc_method_handlers = {
            'GetFeature': grpc.unary_unary_rpc_method_handler(
                    servicer.GetFeature,
                    request_deserializer=route__guide__pb2.Point.FromString,
                    response_serializer=route__guide__pb2.Feature.SerializeToString,
            ),
    }
    generic_handler = grpc.method_handlers_generic_handler(
            'route_guide_simple.RouteGuide', rpc_method_handlers)
    server.add_generic_rpc_handlers((generic_handler,))

 # This class is part of an EXPERIMENTAL API.
class RouteGuide(object):
    """the route guide service
    """

    @staticmethod
    def GetFeature(request,
            target,
            options=(),
            channel_credentials=None,
            call_credentials=None,
            insecure=False,
            compression=None,
            wait_for_ready=None,
            timeout=None,
            metadata=None):
        return grpc.experimental.unary_unary(request, target, '/route_guide_simple.RouteGuide/GetFeature',
            route__guide__pb2.Point.SerializeToString,
            route__guide__pb2.Feature.FromString,
            options, channel_credentials,
            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)

Code Elements

gRPC 生成的代码首先导入 grpc 包和由 protoc 合成的纯 _pb2 模块,后者定义了非 gRPC 特定的代码元素,比如对应于协议缓冲消息的类和反射使用的描述符。

对于.proto 文件中的每个服务 Foo,会生成三个主要元素:

  • Stub:RouteGuideStub被客户端用于连接gRpc服务
  • Servicer:RouteGuideServicer被服务端用于实现gRpc服务
  • Registration Function: add_RouteGuideServicer_to_server函数用于向grpc. Server对象注册服务者。

Stub

生成的 Stub 类由 gRPC 客户端使用。它具有一个构造函数,它使用grpc. Channel对象并初始化存根。对于服务中的每个方法,初始化器向具有相同名称的存根对象添加对应的属性。根据RPC类型(一元或流式),该属性的值将是UnaryUnaryMultiCallable,UnaryStreamMultiCallable,StreamUnaryMultiCallable或StreamStreamMultiCallable类型的可调用对象。

Servicer

对于每个服务,将生成一个 Servicer 类,作为服务实现的超类。对于服务中的每个方法,将在 Servicer 类中生成对应的函数。使用服务实现重写此函数。.proto 文件中注释与代码元素相关联,在生成的 python 代码中以 docstring 的形式出现。

Registration Function

对于每个服务,都会生成一个函数,该函数在grpc. Server对象上注册一个实现该服务的Servicer对象,以便服务器可以将查询路由到相应的服务器。这个函数接受一个实现 Servicer 的对象,通常是上面描述的生成的 Servicer 代码元素的一个子类的实例,以及一个 grpc. Server 对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容

  • 最近在用 python 写项目,项目中有许多 AI 服务需要相互调用,为了服务之间的解耦合,想尝试采用 gRPC ...
    zidea阅读 5,308评论 1 14
  • 本文转载自用Golang构建gRPC服务[https://zhuanlan.zhihu.com/p/8550838...
    雪域迷影阅读 1,945评论 0 0
  • GRPC简介 A high-performance, open-source universal RPC fram...
    臻甄阅读 5,039评论 2 5
  • 该篇文章介绍了golang的grpc编程。 通过下面的例子,你将会学到:1. 在一个.proto文件里define...
    晓_7611阅读 1,383评论 0 3
  • date: 2018-5-15 22:12:32title: grpc| python 实战 grpcdescri...
    daydaygo阅读 78,123评论 9 44