关于如何编写Python grpc服务这里不再赘述,网上有很多资源可供大家参考,今天讲下调用grpc服务遇到的问题。
一个简单的grpc服务
proto文件
//syntax是指定使用哪一种protobuf服务, 现在使用的都是"proto3"
syntax = "proto3";
//包名, 这个不是很重要
package test;
//编写服务, 每个服务里面有相应的函数(对应restful视图函数)
//service表示创建服务
service Matsuri {
//使用rpc定义函数
rpc hello_matsuri(request) returns (JSONResponse){}
}
//所以我们是创建了一个名为Matsuri的服务, 服务里面有一个hello_matsuri的函数
//函数接收一个名为request的参数, 并返回一个response, 至于结尾的{}我们后面再说
//另外参数request、返回值response是哪里来的呢? 所以我们还要进行定义
//注意: request虽然是参数, 但我个人更愿意把它称之为参数的载体
//比如下面定义两个变量name和age, 客户端会把它们放在request里面, 在服务端中也会通过request来获取
message request {
string name = 1; // = 1表示第1个参数
int32 age = 2;
int32 from = 3;
}
//JSONResponse同理, 虽然它是返回值, 但我们返回的显然是result, 只不过需要放在JSONResponse里面
//具体内容在代码中会有体现
message JSONResponse {
string result = 1; //统一返回json字符串作处理
}service.py
# -*- coding: utf-8 -*-
# @Time : 2021/4/28 下午12:16
# @Author : chenshiyang
# @Email : chenshiyang@blued.com
# @File : service.py
# @Software: PyCharm
# 服务端
# 导入grpc第三方库
import json
import grpc
# 导入自动生成的两个py文件
import matsuri_pb2 as pb2
import matsuri_pb2_grpc as pb2_grpc
# 我们在protobuf里面创建的服务叫Matsuri, 所以会给我们提供一个名为MatsuriServicer的类
# 我们直接继承它即可, 当然我们这里的类名叫什么就无所谓了
class Matsuri(pb2_grpc.MatsuriServicer):
# 我们定义的服务里面有一个hello_matsuri的函数
def hello_matsuri(self, request, context):
"""
request就是相应的参数(载体): name、age都在里面
:param request:
:param context:
:return:
"""
name = request.name
age = request.age
# 里面返回是response, 这个response内部只有一个字符串类型的result
result = f"name is {name}, {age} years old, from {source}"
# result需要放在response里面
json_response = pb2.JSONResponse()
json_response.result = json.dumps({"result": result})
return json_response
if __name__ == '__main__':
# 创建一个gRPC服务
# 里面传入一个线程池, 我们这里就启动4个线程吧
from concurrent.futures import ThreadPoolExecutor
grpc_server = grpc.server(ThreadPoolExecutor(max_workers=4))
# 将服务注册到gRPC服务中
pb2_grpc.add_MatsuriServicer_to_server(Matsuri(), grpc_server)
# 绑定ip和端口
grpc_server.add_insecure_port("127.0.0.1:22333")
# 启动服务
grpc_server.start()
# 注意: 如果直接这么启动的话, 会发现程序启动之后就会立刻停止
# 个人猜测, 里面的线程应该是守护线程, 主线程一结束服务就没了
# 所以我们采用一个死循环
import time
try:
while True:
time.sleep(3600)
except KeyboardInterrupt:
# 当按下Ctrl+C, 终止服务
grpc_server.stop(0)client.py
# -*- coding: utf-8 -*-
# @Time : 2021/4/28 下午12:17
# @Author : chenshiyang
# @Email : chenshiyang@blued.com
# @File : client.py
# @Software: PyCharm
# 客户端
import grpc
import matsuri_pb2 as pb2
import matsuri_pb2_grpc as pb2_grpc
# 定义一个频道, 连接至服务端监听的端口
channel = grpc.insecure_channel("127.0.0.1:22333")
# 生成客户端
client = pb2_grpc.MatsuriStub(channel=channel)
# 然后我们就可以直接调用Matsuri服务里面的函数了
print("准备使用服务了~~~~")
while True:
name, age, source = input("请输入姓名和年龄, 并使用逗号分割:").split(",")
response = client.hello_matsuri(pb2.request(name=name, age=int(age), from=source))
# result位于返回值response中, 直接通过属性访问的形式获取
print(response.result)不知道大家有没有发现问题,proto里定义的from字段是python的关键字,client调用的时候关键字冲突语法错误

问题解决
python grpc 解决client调用错误,需要用到setattr函数,给pb2.request()设置from属性,不直接用pb2.request()传参,更改之后的client内容

结果

最后
grpc是跨语言的,在定义proto文件的时候难免会和开发语言的关键字冲突,有的语言关键字冲突(C,C++)grpc自动帮你转成别的了,有的需要你自己去分析解决这个冲突带来的调用问题。





Comments | NOTHING