python简单使用grpc

2023-03-06 18:56:03 浏览数 (2)

# 0. 相关链接

源码案例:https://github.com/tenqaz/python-examples (opens new window)

官方文档:https://grpc.io/docs/languages/python/quickstart (opens new window)

# 1. 创建protobuf文件

在目录proto目录下创建user.proto文件,创建User的rpc服务定义,该服务中包含AddUser和GetUser两个调用,并使用下面创建的对应的结构体作为请求体和响应体。 注意:需要添加package proto,否则下面编译生成的python文件引用路径则不正确。

代码语言:javascript复制
syntax = "proto3";

// 包名
package proto;

// 定义User rpc服务
service User {
  // 定义rpc服务的方法
  rpc AddUser (UserRequest) returns (UserResponse);
  rpc GetUser (GetUserRequest) returns (GetUserResponse);
}

// 请求的结构体
message UserRequest {
  string name = 1;
  uint32 age = 2;
}

// 响应的结构体
message UserResponse {
  string msg = 1;
  int32 code = 2;
}

message GetUserRequest {
  string name = 1;
}

message GetUserResponse {
  string name = 1;
  string age = 2;
}

# 2. 编译proto文件

首选需要安装grpc的库和工具

代码语言:javascript复制
python -m pip install grpcio #安装grpc
python -m pip install grpcio-tools #安装grpc tools

然后,运行命令对proto文件进行编译,会根据上面的proto文件生成对应的python文件,你会发现在proto目录下创建了user_pb2.pyuser_pb2_grpc.py两个文件

代码语言:javascript复制
python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I. ./proto/user.proto
  • --python_out=.,protobuf相关代码文件生成在这里
  • --grpc_python_out=.,grpc相关代码生成在这里
  • -I. ./proto/user.proto,proto文件路径

编译后:

  • user_pb2.py,用来和 protobuf 数据进行交互,这个就是根据proto文件定义好的数据结构类型生成的python化的数据结构文件
  • user_pb2_grpc.py: 用来和 grpc 进行交互,这个就是定义了rpc方法的类,包含了类的请求参数和响应等等,可用python直接实例化调用

# 3. 简单测试protobuf数据结构的序列化与反序列化

我们创建proto_test.py文件,创建User对象,填充值,并将该对象序列化成字符串输出

代码语言:javascript复制
from proto import user_pb2

# 创建Student对象,将该对象序列化成字符串
s = user_pb2.UserRequest()
s.name = "zhangsan"
s.age = 12
req_str = s.SerializeToString()
print(req_str)

输出:

代码语言:javascript复制
b'nx08zhangsanx10x0c'

然后我们再创建User对象将将上面的输出的序列化字符串反序列化进来。

代码语言:javascript复制
# 将上面的输出的序列化字符串反序列化成对象
s2 = user_pb2.UserRequest()
s2.ParseFromString(req_str)
print(s2.name)
print(s2.age)

输出:

代码语言:javascript复制
zhangsan
12

# 4. 创建grpc服务端

下面是使用之前创建的protobuf和grpc文件来构建grpc服务端代码。

代码语言:javascript复制
import logging
from concurrent import futures

import grpc

from proto import user_pb2, user_pb2_grpc


class UserService(user_pb2_grpc.UserServicer):

    # 实现proto文件中rpc的调用
    def AddUser(self, request: user_pb2.UserRequest, context):
        return user_pb2.UserResponse(msg='add user(name={},age={}) success'.format(request.name, request.age), code=0)

    def GetUser(self, request: user_pb2.GetUserRequest, context):
        return user_pb2.GetUserResponse(name=request.name, age="1888")


def serve():
    # 使用线程池来完成grpc的请求
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=5))
    user_pb2_grpc.add_UserServicer_to_server(UserService(), server)
    server.add_insecure_port('[::]:50051')  # 绑定端口
    server.start()
    server.wait_for_termination()


if __name__ == '__main__':
    logging.basicConfig()
    serve()

运行该服务端,会阻塞等待客户端的请求。

# 5. 创建grpc客户端

代码语言:javascript复制
import logging

import grpc

from proto import user_pb2, user_pb2_grpc


def run():
    # 连接rpc服务
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = user_pb2_grpc.UserStub(channel)

        # 调用rpc服务的AddUser方法
        response: user_pb2.UserResponse = stub.AddUser(user_pb2.UserRequest(name="zhangsan", age=18))
        print("add user, response is 'msg={}, code={}'".format(response.msg, response.code))

        # 调用rpc服务的GetUser方法
        response: user_pb2.GetUserResponse = stub.GetUser(user_pb2.GetUserRequest(name="lisi"))
        print("get user[name={}, age={}]".format(response.name, response.age))


if __name__ == '__main__':
    logging.basicConfig()
    run()

运行客户端,调用rpc服务,输出:

代码语言:javascript复制
add user, response is 'msg=add user(name=zhangsan,age=18) success, code=0'
get user[name=lisi, age=1888]

0 人点赞