文件说明
#程序目录及文件说明
#####################################
# 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("下载成功!")