在python中使用grpc和protobuf
簡介
在python中使用grpc和protobuf,比java和c#中使用要簡單一些。只需要先安裝grpcio包,然后就可以應(yīng)用了。
安裝
使用pip安裝grpcio依賴包;
$ pip install grpcio Collecting grpcioDownloading 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安裝時(shí),自動地安裝了protobuf工具包。
定義protobuf
下面定義一個(gè)簡單的protobuf文件,在其中聲明一個(gè)grpc服務(wù)。
創(chuàng)建一個(gè)proto目錄,并在其中創(chuàng)建grpchello.proto文件,如下內(nèi)容。
Note:
- 其實(shí)這個(gè)protobuf定義文件,在我們的java、c#版本示例中使用了,而且各版本的服務(wù)和客戶端可以正常通行調(diào)用。
編譯protobuf
使用protobuf的編譯器,為我們生成python版本的Message定義和服務(wù)的架手腳。
python -m grpc_tools.protoc -I./proto --python_out=. --grpc_python_out=. grpchello.proto在當(dāng)前目錄下,生成2個(gè)文件:
- grpchello_pb2.py
- grpchello_pb2_grpc.py
可以看看這2個(gè)文件:
首先消息定義文件:
# 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 _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('\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'] = _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服務(wù)定義
# 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 filepassdef __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 filepassdef SayHello(self, request, context):# missing associated documentation comment in .proto filepasscontext.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服務(wù)架手腳定義中,定義了gRPCStub,這是給client端使用,調(diào)用grpc服務(wù)的。
- 定義的服務(wù)類gRPCServicer,方法SayHello需要我們在子類中進(jìn)行實(shí)現(xiàn)。定義的add_gRPCServicer_to_server方法,用于把實(shí)現(xiàn)的類和grpc API調(diào)用注冊起來。
這里使用的幾個(gè)主要方法(類):
- 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.
實(shí)現(xiàn)服務(wù)
在我們的實(shí)現(xiàn)服務(wù)的類中,使用服務(wù)方法,并在網(wǎng)絡(luò)中暴露出來。
# -*- 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 * 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個(gè)實(shí)現(xiàn):
- 1、在grpc的API的實(shí)現(xiàn)(服務(wù)實(shí)現(xiàn)類)gRPCServicerImpl中,實(shí)現(xiàn)SayHello方法。
- 2、然后,定義網(wǎng)絡(luò)服務(wù)和端口,把grpc的API注冊到網(wǎng)絡(luò)服務(wù)的處理上。這里簡單利用了grpc.server類。
使用客戶端client
在客戶端,調(diào)用grpc的服務(wù)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、 客戶端使用服務(wù)的Stub,調(diào)用API。
測試
分別啟動服務(wù),然后再啟動客戶端,可以看到調(diào)用結(jié)果。
也可以啟動java、c#版本的grpc服務(wù)端、客戶端,都能調(diào)用成功。
總結(jié)
以上是生活随笔為你收集整理的在python中使用grpc和protobuf的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在C#中使用gRPC及protobuf简
- 下一篇: 在VS.NET 的项目中使用生成事件