grpc协议概述
grpc是一种基于某种协议实现不同机器间进行通信的服务框架。不同机器可以是不同的服务端、客户端,当服务端实现好某些功能后,提供一个服务接口,供不同客户端进行接口调用,从而让不同客户端都能够“享用”到服务端提供的功能。在实际业务场景,比如我是做算法的,那么当我的模型训练完成后,要放到线上让别人调用,则经常是以grpc的方式进行实现的。简单流程就是我写个服务端,实现接收客户端传来的数据,并进行模型推理计算,计算结果再返回客户端,那么客户端实际只需要提供数据即可得到它们想要的结果,中间数据的处理过程均由服务端来完成。
搭建通信过程
协议文件
定义一个文件名为recevicedata.proto文件(可能需要下载插件以识别这个文件),并输入以下代码
// 这里我们用的是proto3版本,版本号是一定要指定的哦!
syntax = "proto3";
import "google/protobuf/wrappers.proto";
service LabelService {
/**
样本集接口
*/
rpc receiveSample(SampleRequestList) returns (google.protobuf.BoolValue) {}
}
message SampleRequestList {
repeated SampleRequest reqList = 1;
}
message SampleRequest {
/**
标签值
*/
string labelValue = 1;
/**
样本集数据
*/
string text = 2;
}
运行以下命令
python -m grpc_tools.protoc -I. --python_out=../grpc_file --grpc_python_out=../grpc_file receivedata.proto
会在grpc_file文件目录下生成两个python文件
服务端
创建server.py文件,输入:
import logging
import sys
sys.path.append('..')
import time
import datetime
from concurrent import futures
import grpc_file
import jieba
import re
import grpc
from grpc_file import ReceiveData_pb2_grpc
# 这个地方的BoolValue可能会飘红,不用管,用就行了
from google.protobuf.wrappers_pb2 import BoolValue
jieba.setLogLevel(log_level=0)
pattern = re.compile('(?:https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]')
logger = logging.getLogger('logger')
# 设置日志等级_
logger.setLevel(logging.INFO)
class ReceiveDataServer:
def __init__(self, host, port):
self.host = host
self.port = port
def match_url(self, text):
"""
去除url
:param text:
:return:
"""
clear = pattern.sub('', text)
return clear
def seg_sentence(self, data):
"""
分词
:param data:
:return:
"""
data = self.match_url(data)
seg_text = jieba.cut(data.replace('\t', '').replace('\n', '').replace(' ', ''))
context = ' '.join(seg_text)
return context
def receiveSample(self, request, context):
"""
接收数据的grpc服务接口,该函数的名称要和proto文件中定义的接口名保持一致
:param request:
:param context:
:return:
"""
requestlist = request.reqList
try:
for item in requestlist:
text = item.text.replace('\n', '。').replace('\r', '。')
text = self.seg_sentence(text)
print(datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S'),
'*** 添加标签:{},添加文本:{}... ***'.format(item.labelValue, text[:10]))
return BoolValue(value=True)
except:
return BoolValue(value=False)
def serve(host, port):
# 启动 rpc 服务
server = grpc.server(futures.ThreadPoolExecutor(max_workers=8))
ReceiveData_pb2_grpc.add_LabelServiceServicer_to_server(ReceiveDataServer(host, port), server)
server.add_insecure_port('{}:{}'.format(host, port))
server.start()
print('Grpc server connect successful!')
try:
while True:
time.sleep(600)
print(datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S'))
except KeyboardInterrupt:
print(datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d %H:%M:%S'))
server.stop(0)
if __name__ == '__main__':
# host和port写上服务端运行的机器ip和端口;
serve(host='xxx.xxx.xxx.xxx', port=50001)
客户端
创建client.py 文件,输入:
import sys
sys.path.append('..')
import grpc
from grpc_file import ReceiveData_pb2, ReceiveData_pb2_grpc
def run():
# 连接 rpc 服务器,ip和端口号必须和服务端设置的一致
channel = grpc.insecure_channel('192.xxx.xxx.xx:50001')
# 调用 rpc 服务
stub = ReceiveData_pb2_grpc.LabelServiceStub(channel)
requestlist = ReceiveData_pb2.SampleRequestList()
for data in range(10):
label = str(data)
text = '第{}个标签的数据'.format(label)
# 由于我们在proto文件中定义的接收数据格式为List,所以这里我们需要先定义一个向List中添加数据的对象
request = requestlist.reqList.add()
request.labelValue = label
request.text = text
response = stub.receiveSample(requestlist)
print(response)
if __name__ == '__main__':
run()
最后运行server.py和client.py文件,会得到以下输出
至此,一个简单的grpc协议搭建完成。