一、思路

emmm:使用docket创建的容器作为服务器端运行python程序,本地项目可以嵌入客户端代码,在有需要时调用服务器端处理发送过去的图片,由于是docker部署,所以可以同时运行很多个待用。
步骤:

二、实现步骤

1、服务器端代码

#!/usr/bin/env python
# -*- coding=utf-8 -*-
import socket
import threading
import time
import sys
import os
import struct

from PIL import Image
import pytesseract
import cv2 as cv

def socket_service():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # AF_INET:IPV4,SOCK_STREAM:TCP形式传输。
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #用于任意类型、任意状态套接口的设置选项值。第一个参数:标识一个socket的描述字。第二个想要套接字级别上设置选项,就必须把level设置为 SOL_SOCKET。
        host = socket.gethostname() # 获取本地主机名
        s.bind((host, 12345))  # HOST,PORT,套接字绑定的IP与端口
        # 这里换上自己的ip和端口,#如果客户端有连接请求,必须使用此函数来接受客户端的请求。存放客户端的地址,区域长度
        # 只有用户进程想与一个具体的地址或端口相关联的时候才需要调用这个函数。如果用户进程没有这个需要,那么程序可以依赖内核的自动的选址机制来完成自动地址选择
        s.listen(10) # 开始TCP监听
    except socket.error as msg:
        print(msg)
        sys.exit(1)
    print("Waiting...")

    while 1:
        conn, addr = s.accept() # 接受TCP连接,并返回新的套接字与IP地址
        t = threading.Thread(target=deal_data, args=(conn, addr))# 创建多线程
        t.start()


def deal_data(conn, addr):
    print('从地址 {0}接收到一个新连接'.format(addr))
    while 1:
        fileinfo_size = struct.calcsize('128sl')# 返回对应于格式化字符串fmt的结构体(以及由pack(fmt, ...)生成的字节对象)的大小。
        buf = conn.recv(fileinfo_size) # 接受文件信息,文件名和大小
        # print('开始传输')
        if buf:
            filename, filesize = struct.unpack('128sl', buf) # 解包。比如pack打包,然后就可以用unpack解包了。返回一个由解包数据(string)得到的一个元组(tuple),
            fn = filename.strip(str.encode('\00')) # 移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。#处理文件名
            new_filename = os.path.join(str.encode('./'), str.encode('new_') + fn) # 修改文件路径
            # print('file new name is {0}, filesize if {1}'.format(new_filename, filesize))

            recvd_size = 0  # 定义已接收文件的大小
            fp = open(new_filename, 'wb') # 二进制可写,file_picture
            print("开始接收...")
            while not recvd_size == filesize: # 检验接受结果
                if filesize - recvd_size > 1024:
                    data = conn.recv(1024)
                    recvd_size += len(data)
                else:
                    data = conn.recv(filesize - recvd_size)
                    recvd_size = filesize
                fp.write(data) # 写文件
            fp.close()
            print("图片接收完成...")
            # 开始处理图片
            # 依赖opencv
            new_filename.decode()
            print('开始图片处理...')
            new_filename = new_filename.decode() # 解码别忘了
            img = cv.imread(new_filename)
            result = pytesseract.image_to_string(Image.fromarray(img))
            print('发送结果...')
            # print(text)
            # conn.send('结果是:' + text)


            # result = 'result:'
            # result.encode() # 传输需要bytes-like object
            conn.send(str.encode(result))
            print("等待下一个...\n\n\n")
        conn.close()
        break


if __name__ == '__main__':
    socket_service()

2、客户端代码

# !/usr/bin/env python
# -*- coding=utf-8 -*-

import socket
import os
import sys
import struct


def socket_client():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #定义socket类型,ipv4,TCP
        # 获取本地主机名
        host = socket.gethostname()
        s.connect((host, 12345)) # 要连接的IP与端口
    except socket.error as msg: # 错误处理
        print(msg)
        sys.exit(1)
    print('开始传输')
    # print(s.recv(1024))

    while 1:
        filepath ='pic2.jpg'
        if os.path.isfile(filepath):
            # 定义定义文件信息。128s表示文件名为128bytes长,l表示一个int或log文件类型,在此为文件大小
            fileinfo_size = struct.calcsize('128sl')
            # 定义文件头信息,包含文件名和文件大小
            fhead = struct.pack('128sl', bytes(os.path.basename(filepath).encode('utf-8')), os.stat(filepath).st_size) # 使用pck打包准备传输
            s.send(fhead) # 传输文件头信息
            print('客户端文件地址: {0}'.format(filepath))
            fp = open(filepath, 'rb') # 只读打开
            while 1:
                data = fp.read(1024)
                if not data:
                    print('{0} 发送完成...'.format(filepath))
                    break
                s.send(data)

            result = s.recv(1024) # 收到识别结果
            print('图片识别结果:', result.decode()[0:-1]) # 解码输出,因为识别出来的字符最后一位有莫名字符,把最后一位去掉。
            # print(result)

        s.close()
        break


if __name__ == '__main__':
    socket_client()



3、首先为服务器端进行docker打包
(1)、新建文件夹python_server
(2)、在文件夹python_server里加入Dockerfile文件

#基于的基础镜像
FROM python:3.6

#代码添加到python_server文件夹,后面可以通过进入容器中看的,注意前面的点代表当前目录,/python_server/code是相对路径目录,点和后面目录注意用空格隔开
ADD . /python_server

# 设置python_server文件夹是工作目录
WORKDIR /python_server

# 安装支持
RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

#当容器启动时,使用python3执行指定路径的py脚本
CMD ["python3", "/py_server.py"]

注意:requirements.txt一定要与运行的python文件在同一目录。
注意:-i https://pypi.tuna.tsinghua.edu.cn/simple是为了下依赖时快一点

(3)、在python_server文件夹里加入requirements.txt

opencv-python
Pillow
pytesseract

备注:获得requirements.txt的方法:
将python文件对应的运行环境激活,然后命令行运行

pip freeze > requirements.txt

它会把这个python环境下pip安装的所有库及版本记录到requirements.txt里。

(4)这一步大坑!
使用以下命令创建一个容器

docker build -t docker_server .

千万不要忘记后面有个点,之间有空格!!
不然会报错

"docker build" requires exactly 1 argument(s).
See 'docker build --help'.

Usage:  docker build [OPTIONS] PATH | URL | -

至于为什么:
此示例指定路径为. 因此,本地目录中的所有文件都被排序并发送到DOCKER守护进程。该路径指定在何处找到DOCKER守护进程上构建的“上下文”的文件

安装结果

Step 5/5 : CMD python3 /py_server.py
 ---> Running in 2499648adbf9
 ---> bc545d18ee29
Removing intermediate container 2499648adbf9
Successfully built bc545d18ee29

(5)、使用以下命令完成容器构建

docker run -it --name server -p 12345:12345 docker_server:latest

附注:docker run 选项大全

-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;

-d: 后台运行容器,并返回容器ID;

-i: 以交互模式运行容器,通常与 -t 同时使用;

-P: 随机端口映射,容器内部端口随机映射到主机的端口

-p: 指定端口映射,格式为:主机(宿主)端口:容器端口

-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;

--name="nginx-lb": 为容器指定一个名称

注意name的引入前面有两条杠。最后一个是镜像仓库名称:TAG
容器运行之后,可以通过宿主机端口12345访问该容器。

(6) 运行准备
容器内啥都没有,很多库需要现装:
1、首先自己安装python

yum install python36

2、自己安装各种库

pip3 install Pillow

3、装opencv_python,安装opencv过程中出现了很多问题,要安装cmake、还要安装下行源码安装工具,编译了半个小时,建议修改图片读取代码,不要用opencv了。
先装安装工具

yum groupinstall 'Development Tools'

再装opencv

pip3 install opencv-python

4、安装tesseract4.1
这玩意花了一天时间没装上,linux装起来太复杂了!服务器tesseract识别部分代码废止,改成服务器端收到图片后直接发送140378,作为模拟,检验互相通信是否成功。

(7) 运行记录
进入容器要使用此命令,可以让服务器端一直在容器运行

docker exec -it 9a3710e5136e /bin/bash

容器ID或名字自己改

在容器内使用

python3 py_server.py

开启服务器端运行,exit退出
在宿主机运行

python3 OCR.py

在这里插入图片描述
调用成功

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐