如何使用Python搭建算法服务端

(PS.若使用出现问题或代码逻辑存在隐患请评论回复,本人接触Socket不多)

如何使用Python搭建算法服务端

现在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()

测试了一下,好像似乎大概没什么问题。

如何使用Python搭建算法服务端

如何使用Python搭建算法服务端

(终于整完了,过五一去了,拜拜)

上一篇:套接字通讯——粘包问题与socketserver模块实现并发


下一篇:TCP 传输数据终极版(解决粘包问题)