最近学习了一下gRPC的使用,所以记录一下
(一)定义*.proto文件,用于生成 gRPC server 和 client使用的代码
// 声明语法版本
syntax = "proto3";
// 定义请求消息体名称和具体消息内容
message PingTask {
string command = 1; // 代表在消息体的第一个位置
string host = 2; // 代表在消息体的第二个位置
int32 times = 3;
string queue = 4;
string exchange = 5;
}
// 定义响应消息体
message PingRes {
string response = 1;
}
// 定义RPC服务
service RenderServer {
// 定义RPC服务接口,需要传入请求消息体和响应消息体
rpc Ping(PingTask) returns (PingRes) {}
}
(二)代码生成
安装protobuf编译器和grpc库:
pip install grpcio-tools
切换到*.proto文件目录下,编译生成代码:
python -m grpc_tools.protoc -I. --python_out=.. --grpc_python_out=.. itcast.proto
-I
表示搜索proto文件中被导入文件的目录--python_out
表示保存生成Python文件的目录,生成的文件中包含接口定义中的数据类型--grpc_python_out
表示保存生成Python文件的目录,生成的文件中包含接口定义中的服务类型
(三)server和client端代码
client.py
# client.py
import render_pb2
import render_pb2_grpc
def invoke_ping(stub, body):
command = body['command']
host = body['host']
times = body['times']
log_queue = body['logs_queue']
log_exchange = body['logs_exchange']
# 构造PingTask请求消息体
ping_task = render_pb2.PingTask(command=command, host=host,
times=times, queue=log_queue,
exchange=log_exchange)
# 调用远程服务器的Ping()接口
res = stub.Ping(ping_task)
print(res.response)
if __name__ == '__main__':
with grpc.insecure_channel("你的远程服务器的ip:port") as channel:
stub = render_pb2_grpc.RenderServerStub(channel)
# 构造PingTask请求消息体需要的数据
body = {}
invoke_ping(stub, body)
server.py
import render_pb2
import render_pb2_grpc
import grpc
from concurrent import futures
class RenderServer(render_pb2_grpc.RenderServerServicer):
def __init__(self):
self.os_platform = platform.system()
# context 用来处理gRPC响应的statuscode
def Ping(self, request, context):
command = request.command
host = request.host
times = request.times
log_queue = request.queue
log_exchange = request.exchange
# 根据操作系统不同构建命令
if self.os_platform == 'Windows':
command = '{command} -n {times} {host}'.format(command=command, host=host, times=times)
elif self.os_platform == 'Linux':
command = '{command} -c {times} {host}'.format(command=command, host=host, times=times)
command = 'python ping_script.py -c "{command}" -q {log_queue} -e {exchange}'.format(
command=command,
log_queue=log_queue,
exchange=log_exchange
)
print("收到命令:{}".format(command))
print("开启一个异步进程去执行脚本,不会收到主进程的影响")
# 返回结果
return render_pb2.PingRes(response="任务正在处理")
def run_server(host=None, port=8888):
# 多线程服务器
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
# 注册本地服务
render_pb2_grpc.add_RenderServerServicer_to_server(RenderServer(), server)
# 监听端口
server.add_insecure_port('{}:{}'.format(host, port))
# 开始接收请求进行服务
server.start()
# 使用 ctrl+c 可以退出服务
try:
time.sleep(1000)
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
print("开启RPC服务,正在监听8888端口")
ip = get_host_ip()
run_server(ip)