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中的应用的更多相关文章

  1. python中grpc配置asyncio使用

    python中grpc配置asyncio使用 安装grpclib pip3 install grpclib protoc编译.proto文件,生成源码文件 python -m grpc_tools.p ...

  2. gRPC Golang/Python使用

    gRPC Golang/Python使用 以前开发网站都是用http协议,学过TCP/IP协议的人都知道,在传输层TCP的基础上,应用层HTTP就是填充了一定规则的文本. 1.gRPC使用和介绍 工作 ...

  3. [转]Python中的str与unicode处理方法

    早上被python的编码搞得抓耳挠腮,在搜资料的时候感觉这篇博文很不错,所以收藏在此. python2.x中处理中文,是一件头疼的事情.网上写这方面的文章,测次不齐,而且都会有点错误,所以在这里打算自 ...

  4. python中的Ellipsis

    ...在python中居然是个常量 print(...) # Ellipsis 看别人怎么装逼 https://www.keakon.net/2014/12/05/Python%E8%A3%85%E9 ...

  5. python中的默认参数

    https://eastlakeside.gitbooks.io/interpy-zh/content/Mutation/ 看下面的代码 def add_to(num, target=[]): tar ...

  6. Python中的类、对象、继承

    类 Python中,类的命名使用帕斯卡命名方式,即首字母大写. Python中定义类的方式如下: class 类名([父类名[,父类名[,...]]]): pass 省略父类名表示该类直接继承自obj ...

  7. python中的TypeError错误解决办法

    新手在学习python时候,会遇到很多的坑,下面来具体说说其中一个. 在使用python编写面向对象的程序时,新手可能遇到TypeError: this constructor takes no ar ...

  8. python中的迭代、生成器等等

    本人对编程语言实在是一窍不通啊...今天看了廖雪峰老师的关于迭代,迭代器,生成器,递归等等,word天,这都什么跟什么啊... 1.关于迭代 如果给定一个list或tuple,我们可以通过for循环来 ...

  9. python2.7高级编程 笔记二(Python中的描述符)

    Python中包含了许多内建的语言特性,它们使得代码简洁且易于理解.这些特性包括列表/集合/字典推导式,属性(property).以及装饰器(decorator).对于大部分特性来说,这些" ...

随机推荐

  1. ELK对Tomcat日志双管齐下-告警触发/Kibana日志展示

    今天我们来聊一聊Tomcat,相信大家并不陌生,tomcat是一个免费开源的web应用服务器,属于轻量级的应用程序,在小型生产环境和并发不是很高的场景下被普遍使用,同时也是开发测试JSP程序的首选.也 ...

  2. Ios还是安卓的判断

    最近在做app的h5页面,涉及到一些小知识点 记录一下 1.微信屏蔽了下载的链接,所以在网页中添加的下载链接都要在浏览器中打开,这里需要一个提示用户在浏览器打开的提示弹框 //判断是否在微信终端打开 ...

  3. UOJ#218. 【UNR #1】火车管理 线段树 主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ218.html 题解 如果我们可以知道每次弹出栈之后新的栈顶是什么,那么我们就可以在一棵区间覆盖.区间求和 ...

  4. 20175312 2018-2019-2 《Java程序设计》结对编程练习_四则运算(第一周:阶段性总结)

    20175312 2018-2019-2 <Java程序设计>结对编程练习_四则运算(第一周:阶段性总结) 结对对象与其博客链接 20175309 刘雨恒:https://www.cnbl ...

  5. 【Vue】-- 数据双向绑定的原理 --Object.defineProperty()

    Object.defineProperty()方法被许多现代前端框架(如Vue.js,React.js)用于数据双向绑定的实现,当我们在框架Model层设置data时,框架将会通过Object.def ...

  6. gdb解决字符串打印果断措施

    在我们进行gdb动态调试的时候,很多时间可能会遇到无法完全显示的情况 关于这种方法网上已经有解决方法 https://blog.csdn.net/shuizhizhiyin/article/detai ...

  7. CSS文字溢出处理问题

    单行省略 div { white-space:nowrap; //断行处理:无断行 text-overflow:ellipsis; //文字溢出处理:省略号 overflow:hidden; //溢出 ...

  8. easy-ui 中的事件触发 (tree)

    easy-ui可以为插件添加事件,但没有触发事件的处理(可能是未找到),所以有时候,我们需要通过程序去触发某个插件指定的事件时,就一筹莫展了 以Tree插件为例 ,添加了onClick事件 jQuer ...

  9. BZOJ4665: 小w的喜糖 DP

    对于这道题,首先每个人的位置并不影响结果 所以我们可以将相同颜色糖果的人放在一块处理 设 $f_{i,j}$ 表示处理到第 $i$ 种糖果至少有 $j$ 人的糖果和原先的类型相同 枚举当前种类中不满足 ...

  10. MyISAM和Innodb区别,为什么?

    事务支持 MyISAM不支持事务,而InnoDB支持. InnoDB的AUTOCOMMIT默认是打开的,即每条SQL语句会默认被封装成一个事务,自动提交,这样会影响速度, 所以最好是把多条SQL语句显 ...