首先上本机实测截图

python 多进程lock 锁传不到方法里_json

如果对linux基础命令都不太熟悉的话,那就先学习基础命令吧,要不然你也不清楚我敲这几个简单的命令是为啥子

下面上服务端的代码

#! /usr/bin/env python3
 
# -*- coding:utf-8 -*-
 
import socket
import threading
import pretty_errors  # 一个错误模块,导入即可,它会把错误的信息显示的五颜六色的
import os, sys, os.path
import time          # 如果是linux服务器,则很有可能需要time.sleep(0.1),原因还不太清楚
import struct        # 本来传输数字应该就这个模块的,但是不太熟,所以最终未用
import json
import readline      # 如果此脚本运行在linux服务器上,为了输入方便,则导入此模块
import signal 
import logging


logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s', filename="fileserver.log") 
pidFile = "/var/run/fileserver.pid"
# 获取socket对象,如果觉得这样写麻烦,可以不用写在方法里面,直接写在外面即可
def sock_obj() -> socket:
    addr_port = ("0.0.0.0", 8989)
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 关闭连接后马上释放端口
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(addr_port)
    s.listen(5)
    return s
 
 
# 这个方法用于接收文件的字节,目前是单线程的,一次只能有一个人上传
# 这里的想法是三步骤:
# 第一步:接收文件名字和大小的字节的长度(有点拗口哈,我也不知道怎么说,反正就是一个数字)
# 第二步:接收实际文件的名字和大小的数据
# 第三步:接收实际文件的内容
def recv_file(sock, addr, dirname) -> None: #这里的 addr参数可以不要,因为我这里未用
    tcp_min_len = 0
    tcp_head_msg = b""
    tcp_head = sock.recv(1024)
    tcp_head_len = struct.unpack(">H", tcp_head)
    time.sleep(0.1)
    while tcp_min_len < int(tcp_head_len[0]):
        msg = sock.recv(1024)
        tcp_min_len += len(msg)
        tcp_head_msg += msg
    #print("%s:%s上传的文件名是:%s,文件大小是:%0.2fG" % (addr[0], addr[1], json.loads(tcp_head_msg.decode("utf-8"))["name"], int(json.loads(tcp_head_msg.decode("utf-8"))["size"]) / 1024 / 1024 / 1024))
    logging.info("%s:%s上传的文件名是:%s,文件大小是:%0.2fG" % (addr[0], addr[1], json.loads(tcp_head_msg.decode("utf-8"))["name"], int(json.loads(tcp_head_msg.decode("utf-8"))["size"]) / 1024 ** 3))
    tcp_head_dict = json.loads(tcp_head_msg.decode("utf-8"))
    file_min_len = 0
    with open(os.path.join(dirname, tcp_head_dict["name"]), "wb") as wf:
        while file_min_len < int(tcp_head_dict["size"]):
            file_data = sock.recv(4096)
            file_min_len += len(file_data)
            wf.write(file_data)
    #print("%s 上传完毕" % json.loads(tcp_head_msg.decode("utf-8"))["name"])
    logging.info("%s 上传完毕" % json.loads(tcp_head_msg.decode("utf-8"))["name"])
 
def while_msg(sock, addr, dir_name) -> None:
    #print("%s:%s进来了" % addr)
    logging.info("%s:%s进来了" % addr)
    while True:
        try:
            recv_file(sock, addr, dir_name)
        except ConnectionResetError:
            #print("%s:%s退出" % addr)
            logging.info("%s:%s退出" % addr)
            break
            

def start_sock(dir_name) -> None:
   print("服务端准备就绪......")
   logging.info("服务端准备就绪......")
   while True:
       sock, addr = sock_obj().accept()
       t = threading.Thread(target=while_msg, args=(sock, addr, dir_name))
       t.start()

def h() -> str:
    h = """    1,脚本用python3编写,未测试是否支持python2
    2,此脚本只能运行再类unix系统上
    ------------------------------------------------
    3,运行此脚本的方式:python3 fileserver.py start
    4,停止此脚本的方式:python3 fileserver.py stop
    """
    print(h)


def get_pid() -> int:
    if os.path.exists(pidFile):
        with open(pidFile, "r") as f:
            return int(f.read())
    else:
        return 0


def set_pid(pid) -> None:
    with open(pidFile, "w") as f:
        f.write(str(pid))
        
        
if __name__ == "__main__":
    if sys.argv[1] == "help":
        h()
    elif sys.argv[1] == "start":
        # 这里大家可以换成参数的形式,我这里就不作了,反正只是测试功能,又不是要完善功能
        #while True:
        #    dir_name = input("please enter dir:")
        #    if not os.path.isdir(dir_name):continue
        #    break
        dir_name = "/opt"
        if os.fork() > 0:
            os._exit(0)
        set_pid(os.getpid())
        start_sock(dir_name)
    elif sys.argv[1] == "stop":
        if get_pid() == 0:print("服务端并未启动")
        else:
            now_pid = os.popen("ps axu | grep %s | grep -v grep" % get_pid()).read()
            if now_pid == "":
                print("服务端并未启动")
                os.popen("rm -rf %s" % pidFile)
            else:
                print("退出进程")
                logging.info("退出进程")
                os.kill(get_pid(), signal.SIGKILL)
                os.popen("rm -rf %s" % pidFile)
    else:
        print("参数错误,使用方法详见 help")

 

下面是客户端的代码

#! /usr/bin/env python3
# -*- coding:utf-8 -*-

import pretty_errors
import os, os.path
import socket
import json
import struct
import time
from tqdm import tqdm


def is_file(path) -> bool:
    if os.path.exists(path):
        if os.path.isfile(path):
            return True
        else:
            return False
    else:
        return False


def get_file_json(path) -> json:
    file_size = os.path.getsize(path)
    file_name = os.path.basename(path)
    file_dict = {"size": file_size, "name": file_name}
    return json.dumps(file_dict)


def send_file(sock) -> None:
    buff_size = 4096
    while True:
        file_path = input("please enter file path:")
        if not is_file(file_path): continue
        break
    file_struct = struct.pack(">H", len(get_file_json(file_path).encode("utf-8")))
    sock.send(file_struct)
    time.sleep(0.1)
    sock.send(get_file_json(file_path).encode("utf-8"))
    time.sleep(0.1)
    with open(file_path, "rb") as rf:
        for i in tqdm(range(int(json.loads(get_file_json(file_path))["size"]) // buff_size + 1)):
            sock.send(rf.read(buff_size))
    print("send end")


if __name__ == "__main__":
    # addr = "172.30.0.161"
    addr = input("please enter id address:")
    port = 8989
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((addr, port))
    while True:
        try:
            send_file(s)
        except ConnectionResetError:
            print("客户端退出")
            break