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('\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服务定义
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服务端、客户端,都能调用成功。
gRPC 在 Python中的应用的更多相关文章
- python中grpc配置asyncio使用
python中grpc配置asyncio使用 安装grpclib pip3 install grpclib protoc编译.proto文件,生成源码文件 python -m grpc_tools.p ...
- gRPC Golang/Python使用
gRPC Golang/Python使用 以前开发网站都是用http协议,学过TCP/IP协议的人都知道,在传输层TCP的基础上,应用层HTTP就是填充了一定规则的文本. 1.gRPC使用和介绍 工作 ...
- [转]Python中的str与unicode处理方法
早上被python的编码搞得抓耳挠腮,在搜资料的时候感觉这篇博文很不错,所以收藏在此. python2.x中处理中文,是一件头疼的事情.网上写这方面的文章,测次不齐,而且都会有点错误,所以在这里打算自 ...
- python中的Ellipsis
...在python中居然是个常量 print(...) # Ellipsis 看别人怎么装逼 https://www.keakon.net/2014/12/05/Python%E8%A3%85%E9 ...
- python中的默认参数
https://eastlakeside.gitbooks.io/interpy-zh/content/Mutation/ 看下面的代码 def add_to(num, target=[]): tar ...
- Python中的类、对象、继承
类 Python中,类的命名使用帕斯卡命名方式,即首字母大写. Python中定义类的方式如下: class 类名([父类名[,父类名[,...]]]): pass 省略父类名表示该类直接继承自obj ...
- python中的TypeError错误解决办法
新手在学习python时候,会遇到很多的坑,下面来具体说说其中一个. 在使用python编写面向对象的程序时,新手可能遇到TypeError: this constructor takes no ar ...
- python中的迭代、生成器等等
本人对编程语言实在是一窍不通啊...今天看了廖雪峰老师的关于迭代,迭代器,生成器,递归等等,word天,这都什么跟什么啊... 1.关于迭代 如果给定一个list或tuple,我们可以通过for循环来 ...
- python2.7高级编程 笔记二(Python中的描述符)
Python中包含了许多内建的语言特性,它们使得代码简洁且易于理解.这些特性包括列表/集合/字典推导式,属性(property).以及装饰器(decorator).对于大部分特性来说,这些" ...
随机推荐
- java实验-3
实验内容 1.XP基础 2.XP核心实践 3.相关工具 实验内容 一.在IDEA中使用工具(Code->Reformate Code)把下面代码重新格式化,再研究一下Code菜单,找出一项让自己 ...
- BZOJ4451 [Cerc2015]Frightful Formula 多项式 FFT 递推 组合数学
原文链接http://www.cnblogs.com/zhouzhendong/p/8820963.html 题目传送门 - BZOJ4451 题意 给你一个$n\times n$矩阵的第一行和第一列 ...
- 基于PySpark的网络服务异常检测系统 (四) Mysql与SparkSQL对接同步数据 kmeans算法计算预测异常
基于Django Restframework和Spark的异常检测系统,数据库为MySQL.Redis, 消息队列为Celery,分析服务为Spark SQL和Spark Mllib,使用kmeans ...
- react + antd 实现打印功能(踩了不少坑)
最近在有网页打印需求,尝试了一下react的打印功能,遇到了不少的坑: 1.react本身有一些打印的组件,但都不好用,都是基于window.print(),但是window.print()如果直接打 ...
- window编程_消息分类
Window应用程序利用Windows消息(Message)与应用程序及系统进行信息交换.消息分为:消息号:有事先定义好的消息名标识字节参数(wParam):用于提供消息的附加信息长字节参数(lPar ...
- BZOJ.4299.Codechef FRBSUM(主席树)
题目链接 记mx为最大的满足1~mx都能组成的数. 考虑当前能构成1~v中的所有数,再加入一个数x,若x>v+1,则mx=v,x不会产生影响:否则x<=v+1,则新的mx=x+v. 对于区 ...
- django——web框架简介
1.web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件. 应用程序有两种模式C/S.B/S.C/S是客户 ...
- __x__(21)0907第四天__ css 盒模型 (框模型)
CSS 处理元素,把每个元素都包含在一个盒子里. 对网页的布局,其实就是对盒子的摆放及设置. 边框border,会使盒子变大: .box{ border: 10px 20px 30px 40px r ...
- ECMA Script 6_Symbol() 唯一类型值声明函数_Symbol 数据类型
Symbol 数据类型 let s = Symbol(); typeof s; // "symbol" 是 ES6 继 Number,String,Boolean,Undefine ...
- (98)Wangdao.com_第三十天_拖拉事件
拖拉事件 拖拉 drag ,是指用户在某个对象上按下鼠标键不放,拖动它到另一个位置,然后释放鼠标键,将该对象放在那里. 一旦某个元素节点的 draggable 属性设为true,就无法再用鼠标选中该节 ...