项目

文件说明

#程序目录及文件说明

#####################################
#   db             数据保存文件夹	  #
#      client      客户端保存文件	  #
#      server      服务器保存文件	  #
#      user_info   用户保存文件      #
#####################################

server.py   服务器运行主文件
app.py      服务器接口文件

client.py   客户端文件
api.py      客户端接口文件

多线程连接,支持并发

server.py

import socket, app, json, struct
from threading import Thread

server = socket.socket()
server.bind(('127.0.0.1', 1688))
server.listen(5)

urls = {
    'login': app.login,
    'register': app.register,
    'upfile': app.upfile,
    'get_file_names': app.get_file_names,
    'download': app.download
}


def connlient(c, addr):
    while True:
        try:
            req = app.recv_data(c)
            # 拿出func判断是否正确的 如果是则调用相应的函数

            func_name = req["func"]
            if func_name in urls:

                # 判断该请求是否是一个上传文件的请求
                if func_name == "upfile":
                    temp_path = app.recv_file(c, req)
                    # 将路径加入到请求数据中 交给应用层来处理
                    req["temp_path"] = temp_path

                resp = urls[func_name](req)  # 调用业务逻辑函数 拿到处理后的结果
                # 这个地方判断返回的数据如果是一个文件路径 那就打开文件发给客户端
                if "file" in resp:
                    print('到这了!!!!')
                    file = resp.pop("file")  # 从响应中取出文件对象

                    app.send_resp(c, resp)  # 发送文件信息给客户端
                    app.send_file(file, c)  # 发送文件数据

                else:  # 表示普通请求
                    app.send_resp(c, resp)  # 发送文件信息给客户端

            else:

                """要调用的函数不存在!"""
                pass

        except Exception as e:
			
            print(f'{addr}断开连接!{e}') # 客户端异常断开连接,直接断开!
            break


print('start...')
while True:
    c, addr = server.accept()
    t = Thread(target=connlient, args=(c, addr)) #有客户端连接,开启线程
    t.start()

app.py

import json, os, struct


# 接收数据
def recv_data(client):
    head_len = client.recv(4)
    if not head_len:
        client.close()
        return

    json_len = struct.unpack('i', head_len)[0]

    # 收真是数据
    json_data = client.recv(json_len)
    if not json_data:
        client.close()
        return
    json_data = json.loads(json_data.decode("utf-8"))
    # print(json_data)
    return json_data


# 发送响应数据
def send_resp(client, resp):
    # 发送请求
    data_json = json.dumps(resp).encode('utf8')
    # 发送长度
    client.send(struct.pack('i', len(data_json)))

    # 发送数据
    client.send(data_json)


def send_filel_list(client, resp):
    # 发送请求
    data_json = json.dumps(resp).encode('utf8')
    # 发送长度
    client.send(struct.pack('i', len(data_json)))

    # 发送数据
    client.send(data_json)


# 接受文件数据,存入硬盘,返回路径
def recv_file(client, request):
    total_size = request['size']
    recv_size = 0

    path = os.path.join('db', 'server', request['name'])
    with open(path, 'wb') as f:
        while recv_size < total_size:
            if total_size - recv_size >= 1024:
                data = client.recv(1024)
            else:
                data = client.recv(total_size - recv_size)
            f.write(data)
            recv_size += len(data)

    path = os.path.abspath(request['name'])
    return path

#登录接口
def login(requester):
    res = os.path.exists(f"db\user_info\{requester['uname']}.json")
    if res:
        with open(f"db\user_info\{requester['uname']}.json", 'r', encoding='utf8') as fr:
            data = json.load(fr)
            if data['pwd'] == requester['pwd']:
                return {'msg': '登录成功', 'flag': True}
            return {'msg': '登录失败,用户名或密码错误', 'flag': False}

    else:
        return {'msg': '登录失败,用户名不存在', 'flag': False}

#注册接口
def register(request):
    res = os.path.exists(f"db\user_info\{request['uname']}.json")
    print(res)
    if res:
        return {'msg': '注册失败,用户名存在', 'flag': False}
    else:
        with open(f"db\user_info\{request['uname']}.json", 'w', encoding='utf8') as fw:
            user_info = {'username': request['uname'], 'pwd': request['pwd']}
            json.dump(user_info, fw)
            fw.flush()
        return {'msg': '注册成功', 'flag': True}


def upfile(requester):
    print(requester)
    return {'msg': '上传成功', 'flag': True}


def get_file_names(requests):
    """返回所有文件列表"""
    names = os.listdir("db\server")
    resp = {"names": names}
    return resp


def download(requests):
    """
    1.接收到请求信息
    2.获取文件的大小返回给客户端
    3.返回的信息中不止包含大小 还包含一个file 是一个文件
    :return:
    """
    path = os.path.join("db", 'server', requests["name"])
    resp = {"size": os.path.getsize(path), "file": open(path, "rb")}

    return resp


def send_file(file, c):
    while True:
        data = file.read(1024)
        if not data:
            break
        c.send(data)

client.py

import api


def run():
    funcs = {"1": api.login, "2": api.register, "3": api.upload, "4": api.download}

    while True:
        print("""
        ------------
        |  1.登录   |
        |  2.注册   |
        |  3.上传   |
        |  4.下载   |
        |  6.退出   |
        ------------
        """)
        f = input("Please choose the function you want:")
        if f == "6":
            print("再见了 勇士!")
            break
        if f in funcs:
            funcs[f]()
        else:
            print("输入不正确! 请重试!")


if __name__ == '__main__':
    run()

api.py

import os, struct, json, socket

client = socket.socket()
client.connect(('127.0.0.1', 1688))
username = {'uname': None}


def send_request(data):
    # 发送请求
    data_json = json.dumps(data).encode("utf-8")
    # 送长度
    client.send(struct.pack("i", len(data_json)))

    # 发送数据
    client.send(data_json)

    # 接收响应数据
    # 收长度
    l = struct.unpack("i", client.recv(4))[0]
    # 收数据
    response = json.loads(client.recv(l).decode("utf-8"))

    return response

#给服务器发送数据,上传
def send_file(path, data):
    data_json = json.dumps(data).encode('utf8')

    client.send(struct.pack('i', len(data_json)))

    client.send(data_json)

    with open(path, 'rb') as f:
        while True:
            data = f.read(1024 * 1)
            if not data:
                break
            client.send(data)

    l = struct.unpack('i', client.recv(4))[0]
    response = json.loads(client.recv(l).decode('utf8'))
    return response

#登录装饰器
def deco(func):
    def wrapper(*args, **kwargs):
        if not username['uname']:
            if login():
                res = func(*args, **kwargs)
                return res
            else:
                print('登录失败')
        else:
            res = func(*args, **kwargs)
            return res

    return wrapper

#登录接口
def login():
    uname = input('uname:').strip()
    pwd = input('pwd:').strip()

    if uname and pwd:
        data = {'uname': uname, 'pwd': pwd, 'func': 'login'}
        resp = send_request(data)
        print(resp)
        msg = resp['msg']
        flag = resp['flag']
        global username  # 全局变量声明
        username = {'uname': uname}  # 登录成功后记录登录名
        print(msg)
        if flag:
            return True
        else:
            return False

#注册接口
def register():
    uname = input('uname:')
    pwd = input('pwd:')

    if uname and pwd:
        data = {'uname': uname, 'pwd': pwd, 'func': 'register'}
        resp = send_request(data)
        print(resp)


@deco
def upload():
    path = input('请输入文件路径:').strip()
    if not os.path.exists(path) or not os.path.isfile(path):
        print('文件路径错误!必须是一个正确的文件路径')
        return

    name = os.path.basename(path)
    size = os.path.getsize(path)

    file_info = {'name': name, 'size': size, 'func': 'upfile'}

    resp = send_file(path, file_info)
    print(resp)


def choose_name():
    req = {"func": "get_file_names"}
    resp = send_request(req)
    # 返回的数据结构 {"names":["张三","李四"]}
    print('/*/*/*/*', resp)
    if not resp["names"]:
        print("暂时没有文件!")
        return
    # 遍历输出
    for k, v in enumerate(resp["names"]):
        print(k, v)
    n = input("请输入序号:").strip()
    if n.isdigit():
        n = int(n)
        if n >= 0 and n < len(resp["names"]):
            filename = resp["names"][n]
            return filename

@deco
def download():
    """
    1.先获取服务器文件列表
    2.选择一个正确文件名称
    3.把文件名称信息发送给服务器
    4.服务器读取文件数据  发送给客户端
    5.客户端接收文件数据
    :return:
    """
    name = choose_name()
    if not name:
        print("没有选择一个正确的文件名称!")
        return
    req = {"name": name, "func": "download"}
    file_info = send_request(req)

    # file_info = {"size":1010110}
    total_szie = file_info["size"]
    recv_size = 0
    path = os.path.join("db", 'client', name)
    f = open(path, "wb")
    while recv_size < total_szie:
        if total_szie - recv_size < 1024:
            data = client.recv(total_szie - recv_size)
        else:
            data = client.recv(1024)
        f.write(data)
        recv_size += len(data)
    f.close()
    print("下载成功!")

原文地址:https://www.cnblogs.com/bladecheng/p/11151840.html