FTP
2023-09-14 09:01:25 时间
python网络编程阶段基础项目
需求分析
请基于TCP协议实现一个网盘系统,包含客户端、服务端,各自需求如下:
- 客户端
- 用户注册,注册成功之后,在服务端的指定目录下为此用户创建一个文件夹,该文件夹下以后存储当前用户的数据(类似于网盘)。
- 用户登录
- 查看网盘目录下的所有文件(一级即可),ls命令
- 上传文件,如果网盘已存在则重新上传(覆盖)。
- 下载文件(进度条)
先判断要下载本地路径中是否存在该文件。
- 不存在,直接下载
- 存在,则让用户选择是否续传(继续下载)。
- 续传,在上次的基础上继续下载。
- 不续传,从头开始下载。
服务端
- 支持注册,并为用户初始化相关目录。
注册成功之后,将所有用户信息存储到特定的Excel文件中
- 支持登录
- 支持查看当前用户网盘目录下的所有文件。
- 支持上传
- 支持下载
README
FTP
环境要求:python3.8
使用方法:
- 启动client.py
- 启动sever.py
功能:
- 注册:适用于新手用户
- 登录:适用于有号者
- 上传文件和下载文件及查看文件前需要登录
代码
客户端
# 客户端
import socket
import json
import os
import time
from conf import setting
user = None # 记录用户是否登录
# 注册功能
def register(client_conn):
name = input('your name:').strip()
pwd = input('your password:').strip()
client_conn.sendall(f'{name}-{pwd}'.encode('utf-8'))
res = json.loads(client_conn.recv(1024).decode('utf-8'))
return res
# 登录功能
def login(client_conn):
global user
name = input('your name:').strip()
pwd = input('your password:').strip()
client_conn.sendall(f'{name}-{pwd}'.encode('utf-8'))
res = json.loads(client_conn.recv(1024).decode('utf-8'))
if res[0] == True:
user = name
return res[1]
return res[1]
# 上传文件
def upload(client_conn):
global user
if not user:
print('请先登录!')
client_conn.sendall('要先登录'.encode('utf-8'))
res = login(client_conn)
return res
else:
file_path = input('请输入要上传的文件路径:').strip()
if not os.path.exists(file_path):
print('文件不存在!')
return
file_name = input('请输入要保存的文件名:').strip()
client_conn.sendall(file_name.encode('utf-8'))
time.sleep(1)
content_size = os.stat(file_path).st_size
client_conn.sendall(json.dumps([user, content_size]).encode('utf-8'))
with open(file_path, mode='rb') as f:
send_size = 0
while True:
cotent = f.read(1024)
client_conn.sendall(cotent)
send_size += len(cotent)
if send_size >= content_size:
break
return client_conn.recv(1024).decode('utf-8')
# 下载文件
def download(client_conn):
global user
if not user:
print('请先登录!')
client_conn.sendall('要先登录'.encode('utf-8'))
res = login(client_conn)
return res
# 发送暗语表示不需要登录
client_conn.sendall('****'.encode('utf-8'))
file_name = input('请输入你要下载的文件名:').strip()
if not os.path.exists(os.path.join(setting.BASE_PATH, '本地下载')):
os.makedirs(os.path.join(setting.BASE_PATH, '本地下载'))
file_path = os.path.join(setting.BASE_PATH, '本地下载', file_name)
client_conn.sendall(json.dumps([file_name, user]).encode('utf-8'))
res = client_conn.recv(1024).decode('utf-8')
print(res)
if res == '没有该文件':
print('网盘内没有该文件!')
return
file_size = int(client_conn.recv(1024).decode('utf-8'))
if not os.path.exists(file_path):
client_conn.sendall('1'.encode('utf-8'))
with open(file_path, mode='wb') as f:
size = 0
while True:
data = client_conn.recv(1024)
f.write(data)
f.flush()
size += len(data)
print('\r{}:{}%'.format(100 * int(size / file_size) * '>', 100 * int(size / file_size)),end='')
if size >= file_size:
break
return client_conn.recv(1024).decode('utf-8')
# 断点续传
else:
client_conn.sendall('2'.encode('utf-8'))
time.sleep(0.5)
exist_size = os.stat(file_path).st_size
client_conn.sendall(str(exist_size).encode('utf-8'))
with open(file_path, mode='ab') as f:
while True:
data = client_conn.recv(1024)
f.write(data)
exist_size += len(data)
print('\r{}:{}%'.format(100 * int(exist_size / file_size)*'>', 100 * int(exist_size / file_size)),end='')
if exist_size == file_size:
break
return client_conn.recv(1024).decode('utf-8')
# 查看文件
def check(client_conn):
if not user:
print('请先登录!')
client_conn.sendall('要先登录'.encode('utf-8'))
login(client_conn)
else:
client_conn.sendall(user.encode('utf-8'))
file_res = json.loads(client_conn.recv(1024).decode('utf-8'))
for file in file_res:
print(file)
# 功能字典
client_dic = {
'0': ['注册功能', register],
'1': ['登录功能', login],
'2': ['上传文件', upload],
'3': ['下载文件', download],
'ls':['查看网盘下文件', check],
}
if __name__ == '__main__':
print('欢迎来到网盘系统'.center(50, '*'))
# 建立链接
while True:
print('正在尝试建立链接...')
try:
client_conn = socket.socket()
client_conn.connect(('127.0.0.1', 8080))
print('连接成功!')
break
except Exception as e:
print('连接失败...')
# 展示可选功能
while True:
for k, v in client_dic.items():
print(f'{v[0]}:{k}')
choice = input('请输入你的选择(输入q退出系统):').strip()
if choice.upper() == 'Q':
print('退出系统!')
break
# 判断用户输入的合法性
if choice not in client_dic or len(choice)==0:
print('请重新输入!')
continue
client_conn.sendall(choice.encode('utf-8'))
if choice == '0':
res = register(client_conn)
print(res[1])
elif choice == '1':
res = login(client_conn)
print(res)
elif choice == '2':
res = upload(client_conn)
print(res)
elif choice == '3':
res = download(client_conn)
print(res)
else:
check(client_conn)
服务端
# 服务端功能
import socket
import os
import json
import time
from conf import setting
from db import db_handler
# 注册功能
def register(conn):
res = conn.recv(1024).decode('utf-8')
print(res)
name, pwd = res.split('-') # 'name-pwd'
dir_path = os.path.join(setting.BASE_PATH, '用户', f'{name}')
# 判断用户文件夹是否存在
if not os.path.exists(dir_path):
os.makedirs(dir_path)
# 将用户注册信息写入文件
file_path = os.path.join(dir_path, 'info.xlsx')
print(file_path)
db_handler.save(name,pwd,file_path)
conn.sendall(json.dumps([True, '注册成功!']).encode('utf-8'))
return
# 用户文件夹存在则表示用户已经注册过
conn.sendall(json.dumps([False, '用户已存在!']).encode('utf-8'))
# 登录功能
def login(conn):
res = conn.recv(1024).decode('utf-8')
print(res)
name, pwd = res.split('-') # 'name-pwd'
dir_path = os.path.join(setting.BASE_PATH, '用户', f'{name}')
# 判断用户文件夹是否存在
if not os.path.exists(dir_path):
conn.sendall(json.dumps(['False', '登陆失败,该用户不存在']).encode('utf-8'))
return '该用户不存在!'
file_path = os.path.join(dir_path, 'info.xlsx')
# 获取用户信息
fname, fpwd = db_handler.check_info(file_path)
if fpwd == pwd:
conn.sendall(json.dumps([True, '登录成功!']).encode('utf-8'))
return True
else:
conn.sendall(json.dumps([False, '登录失败,密码错误!']).encode('utf-8'))
return False
# 上传文件
def upload(conn):
file_name = conn.recv(1024).decode('utf-8')
if file_name == '要先登录':
res = login(conn)
return res
time.sleep(1)
name_size = json.loads(conn.recv(1024).decode('utf-8'))
name, size = name_size[0], name_size[1]
print(name,size)
file_path = os.path.join(setting.BASE_PATH, '用户', name, file_name)
with open(file_path, mode='wb') as f:
recv_size = 0
while True:
data = conn.recv(1024)
f.write(data)
recv_size += len(data)
if recv_size >= size:
conn.sendall('ok!'.encode('utf-8'))
return
# 下载文件
def download(conn):
file_name = conn.recv(1024).decode('utf-8')
if file_name == '要先登录':
res = login(conn)
return res
# 接收文件名、用户名
file_name, user = json.loads(conn.recv(1024).decode('utf-8'))
print(file_name,user)
file_path = os.path.join(setting.BASE_PATH, '用户', user, file_name)
# 判断服务器是否有该文件
if not os.path.exists(file_path):
conn.sendall('没有该文件'.encode('utf-8'))
return
# 发送暗语表示有文件
conn.sendall('*****'.encode('utf-8'))
# 发送文件大小
content_size = os.stat(file_path).st_size
conn.sendall(str(content_size).encode('utf-8'))
send_size = 0
# 区别客户端情况作出不同应答
if conn.recv(1024).decode('utf-8') == '1':
with open(file_path, mode='rb') as f:
while True:
content = f.read(1024)
conn.sendall(content)
send_size += len(content)
if send_size >= content_size:
conn.sendall('OK!'.encode('utf-8'))
break
else:
exist_size = int(conn.recv(1024).decode('utf-8'))
print(exist_size)
with open(file_path, mode='rb') as f:
# 断点续传
f.seek(exist_size)
while True:
data = f.read(1)
conn.sendall(data)
send_size += len(data)
if send_size >= content_size - exist_size:
conn.sendall('ok!'.encode('utf-8'))
return
# 查看文件
def check(conn):
name = conn.recv(1024).decode('utf-8')
print(name)
if name == '要先登录':
login(conn)
else:
file_path = os.path.join(setting.BASE_PATH, '用户', name)
print(file_path)
file_list = os.listdir(file_path)
conn.sendall(json.dumps(file_list).encode('utf-8'))
if __name__ == '__main__':
# 建立TCP链接
client = socket.socket()
client.bind(('127.0.0.1', 8080))
client.listen(5)
conn, addr = client.accept()
while True:
# 接受客户端的命令
choice = conn.recv(1024).decode('utf-8')
print(choice)
if choice == '0':
register(conn)
elif choice == '1':
login(conn)
elif choice == '2':
upload(conn)
elif choice == '3':
download(conn)
else:
check(conn)
注意:仅展示了部分代码,需要私
相关文章
- 通过HTTP服务访问FTP服务器文件(配置nginx+ftp服务器)
- FTP客户端工具
- linux ftp命令参数全集
- 阿里云centos配置ftp和svn全过程
- H3CNE学习---dhcp、telnet、ssh、ftp
- centos 6.5 搭建ftp服务器
- 【FTP资源】发现一个ArcGIS相关的FTP。
- Linux仅可使用SFTP登录到指定目录(无法使用ssh、ftp、telnet)
- 如何在linux下开启FTP服务
- FTP服务器配置
- FTP、WEB虚拟目录作用
- FTP、FTPS和SFTP
- 阿里云服务器怎么查找FTP帐号和密码?
- Qt之高级网络操作(HTTP/FTP快速上手)
- FTP主被动模式连接建立解析
- linux上安装ftp
- Linux CentOS7 安装FTP服务器
- Windows下搭建FTP服务,FileZilla Server