在python中使用grpc和protobuf
来源:互联网 发布:ubuntu挂载网络硬盘 编辑:程序博客网 时间:2024/06/05 11:25
简介
在python中使用grpc和protobuf,比java和c#中使用要简单一些。只需要先安装grpcio包,然后就可以应用了。
安装
使用pip安装grpcio依赖包;
$ pip install grpcioCollecting 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, grpcioSuccessfully 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
在当前目录下,生成2个文件:
- grpchello_pb2.py
- grpchello_pb2_grpc.py
可以看看这2个文件:
首先消息定义文件:
# Generated by the protocol buffer compiler. DO NOT EDIT!# source: grpchello.protoimport sys_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))from google.protobuf import descriptor as _descriptorfrom google.protobuf import message as _messagefrom google.protobuf import reflection as _reflectionfrom google.protobuf import symbol_database as _symbol_databasefrom 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('\n\x0fgrpchello.proto\x12\x08grpcDemo\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2B\n\x04gRPC\x12:\n\x08SayHello\x12\x16.grpcDemo.HelloRequest\x1a\x14.grpcDemo.HelloReply\"\x00\x62\x06proto3'))_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'] = _HELLOREQUESTDESCRIPTOR.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 grpcimport grpchello_pb2 as grpchello__pb2class 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 grpcimport timefrom concurrent import futures import grpchello_pb2, grpchello_pb2_grpc_HOST = 'localhost'_PORT = '8188'_ONE_DAY_IN_SECONDS = 60 * 60 * 24class 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_functionimport grpcfrom grpchello_pb2 import * ## or import grpchello_pb2from 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服务端、客户端,都能调用成功。
- 在python中使用grpc和protobuf
- java中使用grpc和protobuf
- 在C#中使用gRPC及protobuf简介
- Go实战--golang中使用gRPC和Protobuf实现高性能api(golang/protobuf、google.golang.org/grpc)
- Protobuf和GRPC(一)
- 在protobuf中使用python的extension
- Android项目使用 protobuf和grpc简单例子
- protobuf + grpc 使用入门 一
- protobuf + grpc 使用入门 二
- python中使用protobuf
- 【python+protobuf】在python中使用protocol buffer
- Protobuf在Python中的使用
- Protobuf在Python中的使用
- 在c++中使用protobuf
- 在 Golang 中使用 Protobuf
- 在 Golang 中使用 Protobuf
- 在Unity5中使用Protobuf
- 在egret中使用protobuf
- java.lang.IllegalStateException:Make sure the content of your adapter is not modified from a backgro
- Virtualenv简介
- [BZOJ3993][SDOI2015]星际战争(二分答案+最大流)
- MTK手机官方ROM提取教程
- Nodejs 创建文本文件和Excel文件
- 在python中使用grpc和protobuf
- AssetBundle
- 第九届山东理工大学ACM网络编程擂台赛 热身赛 sdut4087 ldq's Sons
- caffe ssd
- Spring的各种PostProcessor
- 基于cefsharp的浏览器应用开发(支持XP系统)
- 桌面门户与单点登录简要介绍
- gdb获取进程的全局变量
- 分事事务之异步确保性(二)