Python grpc 关键字冲突

发布于 2021-04-29  1,226 次阅读


关于如何编写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自动帮你转成别的了,有的需要你自己去分析解决这个冲突带来的调用问题。


一名测试工作者,专注接口测试、自动化测试、性能测试、Python技术。