(PS.若使用出现问题或代码逻辑存在隐患请评论回复,本人接触Socket不多)
现在AI算法大多数会部署在Linux系统上,但Linux系统上的图形界面非常不人性化,不适合直接给客户进行展示。所以我们希望在Windows系统上做应用客户端,在Linux系统上做算法服务器。大概的流程如上图所示。
大概描述一下两个服务的交互关系:
1、应用服务向算法服务发送连接
2、算法服务创建数据处理线程
3、应用服务与数据处理线程1对1通信。(下面的代码只支持1个客户端的连接,多个客户端不想写了,以后有空在玩吧)
--------------------------------------------------------------------------------
本文测试环境:
Ubuntu16.04 IP地址192.168.1.105
Win8.1 IP地址192.168.1.107
算法服务的通信端口7788
--------------------------------------------------------------------------------
Linux算法服务代码:
from socket import *
import numpy as np
from threading import Thread, Lock
import alg #自己的算法
global_lock = Lock()
global_pool = []
def check_head(data):
if data.count(b'Flag') == 2:
cmds = data.split(b':')
if cmds[0]==b'Flag' and cmds[1]==b'CMD' and cmds[3]==b'Length':
return cmds
else:
return False
else:
return False
def socket_recv_image(socket, recv_data):
# data有可能和head一起被接收到
# 所以总长度是需要接收的长度减去head后面那部分数据长度
total_data = recv_data.split(b'Flag')[2]
img_length = int(recv_data.split(b':')[4])-len(total_data)
recv_len = 0
while recv_len<img_length:
try:
recv_data = socket.recv(1024)
except:
return np.array([])
recv_len += len(recv_data)
total_data += recv_data
img_data = np.asarray(bytearray(total_data), dtype=np.uint8)
return img_data
def socket_send_result(socket, feat):
feat = feat.tostring()
feat_len = len(feat)
head = 'Flag:CMD:RESULT:Length:{}:Flag'.format(feat_len)
try:
socket.send(head.encode())
socket.send(feat)
except:
return False
return True
def thread_proc(client_socket, client_Addr):
global global_lock
global global_pool
while True:
try:
recv_data = client_socket.recv(1024)
except:
break
check_results = check_head(recv_data)
if check_results:
if check_results[2] == b'IMAGE_PROC':
img_data = socket_recv_image(client_socket, recv_data) # 接收图像数据
if img_data.size == 0:
break
feat = alg.get_feature(img_data) # 服务器对图像进行处理
if socket_send_result(client_socket, feat) != True: # 发送处理结果
break
elif check_results[2] == b'CLOSE_SOCKET':
break
else:
continue
client_socket.close()
global_lock.acquire()
global_pool.remove(client_Addr[1])
global_lock.release()
print('Exit by peer: IP({}) Port({})'.format(client_Addr[0], client_Addr[1]))
def main():
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
address = ('', 7788)
tcp_server_socket.bind(address)
tcp_server_socket.listen(1)
global global_lock
global global_pool
while True:
global_lock.acquire()
have_resource = len(global_pool)<1
global_lock.release()
if have_resource:
print('\nwaiting connect...')
client_socket, client_Addr = tcp_server_socket.accept()
print('client connect: IP({}) Port({})'.format(client_Addr[0], client_Addr[1]))
global_lock.acquire()
global_pool.append(client_Addr[1])
global_lock.release()
t = Thread(target=thread_proc, args=(client_socket, client_Addr,))
t.start()
tcp_server_socket.close()
if __name__ == '__main__':
main()
Windows应用测试代码
import os
from socket import *
import cv2 as cv
import numpy as np
def open_connect(socket, server_ip, server_port):
try:
socket.connect((server_ip, server_port))
return True
except:
return False
def close_connect(socket):
head = 'Flag:CMD:CLOSE_SOCKET:Length:0:Flag'
socket.send(head.encode())
socket.close()
return True
def socket_send_image(socket, img, img_type='.jpg'):
img_encode = cv.imencode(img_type, img)[1]
data_encode = np.array(img_encode)
data_len = len(data_encode)
head = 'Flag:CMD:IMAGE_PROC:Length:{}:Flag'.format(data_len)
socket.send(head.encode())
socket.send(data_encode)
def socket_recv_result(socket):
recv_data = socket.recv(1024)
cmd = recv_data.split(b':')
if recv_data.count(b'Flag')==2 and cmd[0]==b'Flag' and cmd[2]==b'RESULT':
total_data = recv_data.split(b'Flag')[2]
feat_length = int(cmd[4])-len(total_data)
recv_len = 0
while recv_len<feat_length:
recv_data = socket.recv(1024)
recv_len += len(recv_data)
total_data += recv_data
feat = np.fromstring(total_data, dtype=np.float32)
return feat
else:
return np.array([])
def main():
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
if open_connect(tcp_client_socket,'192.168.1.105',7788) == False:
print('connect error!')
exit()
else:
print('connected!')
img_list = os.listdir('E:/[4]datasets/MSCOCO/query')
for img_name in img_list:
img = cv.imread('E:/[4]datasets/MSCOCO/query/' + img_name)
socket_send_image(tcp_client_socket, img)
feat = socket_recv_result(tcp_client_socket)
print('{} {}'.format(len(feat), img_name))
close_connect(tcp_client_socket)
if __name__=='__main__':
main()
测试了一下,好像似乎大概没什么问题。
(终于整完了,过五一去了,拜拜)