Grpc的安装和原理,见官网:https://grpc.io/
由于我的目的是不断地从客户端传输图片到服务器端,然后服务器在每次收到图片后返回结果,所以我用的是:
- 客户端流式RPC,客户端再次使用提供的流写入一系列消息并将其发送到服务器。一旦客户端写完消息,它就等待服务器读取它们并返回它的响应。
下面是我的proto文件,命名为:upload.proto:
syntax = 'proto3';
service Upload {
rpc Fileup(stream Tdata) returns (Tdata) {}
}
message Tdata {
string data = 1;
int64 size = 2;
string name = 3;
}
从.proto服务定义生成gRPC客户端和服务器接口:
$ python -m grpc_tools.protoc -I../../protos --python_out=. --grpc_python_out=. ../../protos/upload.proto
然后就会得到:upload_pb2.py 和 upload_pb2_grpc.py (自动生成的)
接下去实现客户端和服务器端的代码:
客户端:
import threading
import grpc
import time
import codecs
from pprint import pprint
from tqdm import tqdm
import base64
import os
import sys
import argparse
from proto import upload_pb2_grpc
from proto import upload_pb2
import time
import numpy as np
def getfile(path,chunksize):
readsize = 0
filesize = sys.getsizeof(path)
data =[]
if filesize<chunksize:
path=bytes(path)
data.append(base64.b64encode(path))
return data
def run(tf_file, path, ip):
channel = grpc.insecure_channel('{}:50053'.format(ip))
stub = upload_pb2_grpc.UploadStub(channel)
def stream():
for tf in tf_file:
yield upload_pb2.Tdata(data=tf, size=len(tf_file), name=path)
response = stub.Fileup(stream())
# print("received: " + response.data)
# 我这里返回的是字符串,接下去转换成数组
stri = response.data
list = stri.split(" ")
for i in range(len(list)):
list[i] = np.fromstring(list[i], dtype=int, sep=',')
list = np.array(list)
return list
服务器端:
import threading
import grpc
from proto import upload_pb2_grpc
from proto import upload_pb2
import time
from concurrent import futures
import base64
from pprint import pprint
import os
import re
import cv2
import numpy as np
import PIL
class Upload(upload_pb2_grpc.UploadServicer):
def Fileup(self, request_iterator, context):
i=0
file_exist = False
while 1:
for Tdata in request_iterator:
out_ite = Tdata
print(type(out_ite))
binary_data = base64.b64decode(out_ite.data)
if (os.path.exists(out_ite.name) and i == 0) or file_exist:
if i == 0:
print('{} already exists,So no copy this file.'.format(out_ite.name))
file_exist = True
pass
else:
if re.search('/', out_ite.name):
os.makedirs(os.path.dirname(out_ite.name), exist_ok=True)
file_name = out_ite.name
else:
file_name = out_ite.name
# 这里我传输的图片是:640*480的三通道彩色图
image = np.fromstring(binary_data, np.uint8).reshape( 480, 640, 3 )
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
cv2.imwrite(file_name, image)
i += 1
if i == out_ite.size and not file_exist:
print('complete! {} '.format(out_ite.name))
print(time.time())
# 事实上要返回的数据结果,是通过图像处理得到的,这里只是举例
list1 = [[100, 200, 300, 400], [12, 120, 133, 140]]
list1 = np.array(list1)
stri = ""
# 将数组转换成字符串
for i in range(len(list1)):
for j in range(len(list1[i])):
stri += "".join(str(list1[i][j]))
if (j < (len(list1[i]) - 1)):
stri += ","
if(i<(len(list1)-1)):
stri += " "
return upload_pb2.Tdata(data=stri, size=out_ite.size, name=out_ite.name)
upload.py:(
import argparse
import client
import server
import threading
import grpc
from concurrent import futures
import time
import os
import re
import sys
from proto import upload_pb2_grpc
from proto import upload_pb2
import numpy as np
# sys.path.append('D:/python/apple-picker/pyuploader')
def server(): # 服务器端
fserver = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
upload_pb2_grpc.add_UploadServicer_to_server(
server.Upload(), fserver)
fserver.add_insecure_port('[::]:50053')
fserver.start()
print('file waiting...')
while 1:
time.sleep(1)
def client_run(read_path, send_path, ip): # 客户端
chunksize = 1000000
tf_file = client.getfile(read_path, chunksize)
lst_box = client.run(tf_file, send_path, ip)
return lst_box
def client_all_image(paths,send_path,ip):
img = paths[0]
filesize = sys.getsizeof(img)
lst_box = client_run(img, send_path, ip)
return lst_box
开启客户端:
def send_file(out, lst_box, ip, close_camera):
"""利用Grpc和视觉系统的通信,传输图片"""
# 这里的out是从相机直接得到的图片
index = 0
while close_camera[0] == 1:
image_name = "ZImage_" + str(index) + ".jpg"
lst_box[0] = client_all_image(out, image_name, ip[0])
lst_box[1] = time.time()
index += 1
time.sleep(5) # 隔5s传一次
服务器端:
直接调用 server方法即可。
这里我传输的是直接从相机得到的图片,如果是传输图片文件需要修改文件读写部分的代码。
祝顺利 :)