FTP开发
要求:
1. 用户加密认证
2. 多用户同时登陆
3. 每个用户有自己的家目录且只能访问自己的家目录
4. 对用户进行磁盘配额、不同用户配额可不同
5. 用户可以登陆server后,可切换目录
6. 查看当前目录下文件
7. 上传下载文件,保证文件一致性
8. 传输过程中现实进度条
9. 支持断点续传
服务器端
__author__ = "Elijah"
__date__ = "2017/9/14 14:15"
import hmac
import json
import os
import pickle
import random
import socketserver
import string
import struct
class ftpserver(socketserver.BaseRequestHandler):
max_packet_size = 8192
coding = 'utf-8'
BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
files_dir = '\\files\\'
config_dir = '\\conf\\'
download_dir = '\\download\\'
def login(self):
'''
用户登陆
:return: user_name
'''
user_exist = False
flag = True
while flag:
print('用户进入登陆功能!即将进行用户名/密码验证......')
with open(self.BASE_DIR + self.config_dir + 'config.txt', mode='rb') as f_r:
config_dict = pickle.load(f_r)
user_name = self.request.recv(1024)
if (user_name == b'q') or (user_name == b'Q'):
self.request.send(bytes('user_name quit', encoding=self.coding))
print('用户在用户名阶段退出登陆功能!')
break
else:
for k, v in config_dict.items():
if k == user_name:
self.request.send(bytes('user_name available', encoding=self.coding))
user_password = self.request.recv(1024)
if (user_password == b'q') or (user_password == b'Q'):
self.request.send(bytes('user_password quit', encoding=self.coding))
print('用户在密码阶段退出登陆功能!')
break
elif user_password == v[0]:
self.request.send(bytes('password available', encoding=self.coding))
client_respond = self.request.recv(1024)
if client_respond == b'get password available':
print('用户' + str(user_name, encoding=self.coding) + '密码正确!即将进行客户端验证......')
self.request.send(self.secret_key())
auth_result = self.request_auth()
if auth_result:
self.request.send(bytes('auth_successful', encoding=self.coding))
print('客户端验证成功!')
flag = False
user_exist = True
break
else:
self.request.send(bytes('auth_failed', encoding=self.coding))
print('客户端验证失败!重新进行登录!')
user_exist = True
break
else:
print('客户端接收密码有效信息有误!')
break
else:
self.request.send(bytes('password wrong', encoding=self.coding))
print('用户输入密码有误!')
user_exist = True
break
else:
continue
if not user_exist:
self.request.send(bytes('user_name wrong', encoding=self.coding))
print('用户名不存在,请重新输入!')
def register(self):
'''
用户注册
:return:
'''
print('用户进入注册功能!')
flag = True
dir_path = self.BASE_DIR + self.config_dir
try:
with open(os.path.join(dir_path, 'config.txt'), 'rb') as f_r:
config_dict = pickle.load(f_r)
except Exception as e:
config_dict = {'': ['', '']}
while flag:
new_user = self.request.recv(1024)
if (new_user == b'q') or (new_user == b'Q'):
self.request.send(bytes('user quit', encoding=self.coding))
print('用户退出注册功能!')
break
elif new_user in config_dict.keys():
self.request.send(bytes('user exist', encoding=self.coding))
print('用户名已经存在,无效用户名!用户重新输入!')
continue
elif new_user not in config_dict.keys():
self.request.send(bytes('user available', encoding=self.coding))
print('用户名有效!')
new_password = self.request.recv(1024)
if (new_password == b'q') or (new_password == b'Q'):
break
else:
print('密码有效,接收上传目录空间配额')
self.request.send(bytes('password_received', encoding=self.coding))
user_space = self.request.recv(1024)
config_dict[new_user] = [new_password, user_space]
with open(self.BASE_DIR + self.config_dir + 'config.txt', mode='wb') as f_w:
pickle.dump(config_dict, f_w)
print('用户' + str(new_user, encoding=self.coding) + '注册成功! 密码为:' + str(new_password,
encoding=self.coding) + ' 用户上传目录空间为:' + str(
user_space, encoding=self.coding))
self.request.send(bytes('Register Successful', encoding=self.coding))
break
else:
print('服务端接受注册用户名有误!')
break
def secret_key(self):
'''
√生成随机校验码,以便进行认证
:return: 6位bytes格式的数字+字母组合校验码
'''
auth_key = string.ascii_lowercase + string.digits
character = random.sample(auth_key, 6)
string_key = "".join(character)
bytes_key = bytes(string_key.encode(self.coding))
return bytes_key
def request_auth(self):
'''
认证客户端链接
:return: 布尔值
'''
print('开始进行客户端验证......')
msg = os.urandom(32)
self.request.send(msg)
key = self.request.recv(1024)
self.request.send(bytes('received', encoding=self.coding))
h = hmac.new(key, msg)
digest = h.digest()
respone = self.request.recv(len(digest))
return hmac.compare_digest(respone, digest)
def get_directorysize(self, file_path, size=0):
'''
查看filePath目录下的文件以及大小,用于判断用户配额
:param filePath:
:param size:
:return:
'''
for root, dirs, files in os.walk(file_path):
for f in files:
size += os.path.getsize(os.path.join(root, f))
return size
def upload(self, head_dic):
'''
文件上传功能
:param args:报头字典{'command': 操作命令, 'file_name': 文件名称, 'file_size': 文件大小,'user_name': 用户名}
:return:
'''
with open(self.BASE_DIR + self.config_dir + 'config.txt', 'rb') as f:
config_dict = pickle.load(f)
space = config_dict[bytes(head_dic['user_name'],encoding=self.coding)][1]
user_space = int(str(space,encoding=self.coding))
while True:
f_name = os.path.basename(head_dic['file_name'])
file_path = self.BASE_DIR + self.files_dir + head_dic['user_name'] + '\\'
try:
os.mkdir(file_path)
except Exception as e:
pass
file_size = head_dic['file_size']
if os.path.exists(os.path.join(file_path, f_name)):
print('用户上传文件已经存在,询问用户是否继续上传...')
self.request.send(bytes('file_already_exist', encoding=self.coding))
is_continue = self.request.recv(1024)
if is_continue == b'continue_upload':
get_existfile_size = os.path.getsize(os.path.join(file_path, f_name))
temp_size = get_existfile_size
self.request.send(bytes(str(get_existfile_size), encoding=self.coding))
with open(os.path.join(file_path, f_name), 'ab') as f:
while temp_size < file_size:
recv_continue_data = self.request.recv(self.max_packet_size)
f.write(recv_continue_data)
f.flush()
temp_size += len(recv_continue_data)
print('文件继续传进度:' + str(round((temp_size / 1024), 2)) + ' KB / ' + str(
round((file_size / 1024), 2)) + ' KB')
print('客户端:' + head_dic['user_name'] + ' 文件:' + f_name + ' 上传完成!')
break
else:
directory_size = self.get_directorysize(file_path)
if (directory_size + file_size) > user_space * 1024 * 1024:
print('用户:' + head_dic['user_name'] + ' 上传文件后目录空间将超过 ' + str(user_space) + ' MB 限额,上传文件失败!')
self.request.send(bytes('Insufficient_directory_space', encoding=self.coding))
client_received = self.request.recv(1024)
if client_received == b'Insufficient_directory_space_received':
self.request.send(space)
break
else:
self.request.send(bytes('Directory_space_available', encoding=self.coding))
recv_size = 0
print('----->', file_path)
with open(os.path.join(file_path, f_name), 'wb') as f_w:
while recv_size < file_size:
recv_data = self.request.recv(self.max_packet_size)
f_w.write(recv_data)
f_w.flush()
recv_size += len(recv_data)
print('文件上传进度:' + str(round((recv_size / 1024), 2)) + ' KB / ' + str(
round((file_size / 1024), 2)) + ' KB')
print('客户端:' + head_dic['user_name'] + ' 文件:' + f_name + ' 上传完成!')
break
def download(self, head_dic):
'''
下载功能
:param head_dic:
:param user_name:
:return:
'''
file_path = self.BASE_DIR + self.files_dir + head_dic['user_name'] + '\\'
while True:
send_size = 0
files_dict = {}
for root, dirs, files in os.walk(file_path):
for f in files:
files_dict[f] = os.path.getsize(os.path.join(root, f))
files_dict_json = json.dumps(files_dict)
files_dict_json_bytes = bytes(files_dict_json, encoding=self.coding)
files_dict_json_bytes_struct = struct.pack('i', len(files_dict_json_bytes))
self.request.send(files_dict_json_bytes_struct)
is_received = self.request.recv(1024)
if is_received == b'files_dict_json_bytes_struct_received':
self.request.send(files_dict_json_bytes)
print('用户:' + head_dic['user_name'] + ' 收到上传目录文件字典!')
else:
print('客户端返回信息有误,请重试!')
break
f_name = self.request.recv(1024)
self.request.send(bytes('file_name_received', encoding=self.coding))
file_path = self.BASE_DIR + self.files_dir + head_dic['user_name'] + '\\'
with open(file_path + str(f_name, encoding=self.coding), 'rb') as f:
for line in f:
self.request.send(line)
send_size += len(line)
print(('文件下载进度:%.2f KB / %.2f KB') % (
send_size / 1024, (files_dict[str(f_name, encoding=self.coding)]) / 1024))
is_finished = self.request.recv(1024)
if is_finished == b'received_finished':
print('文件 ' + str(f_name, encoding=self.coding) + ' 下载完成!\n')
break
else:
print('客户端接收错误,请重试!')
break
def show_dir(self, head_dic):
'''
查看上传目录下文件
:param head_dic:
:param user_name:
:return:
'''
file_path = self.BASE_DIR + self.files_dir + head_dic['user_name'] + '\\'
while True:
files_dict = {}
for root, dirs, files in os.walk(file_path):
for f in files:
files_dict[f] = os.path.getsize(os.path.join(root, f))
files_dict_json = json.dumps(files_dict)
files_dict_json_bytes = bytes(files_dict_json, encoding=self.coding)
files_dict_json_bytes_struct = struct.pack('i', len(files_dict_json_bytes))
self.request.send(files_dict_json_bytes_struct)
is_received = self.request.recv(1024)
if is_received == b'files_dict_json_bytes_struct_received':
self.request.send(files_dict_json_bytes)
print('用户:' + head_dic['user_name'] + ' 收到上传目录文件字典!')
break
else:
print('客户端返回信息有误,请重试!')
break
def delete_file(self, head_dic):
'''
删除用户目录文件
:param head_dic:
:return:
'''
file_path = self.BASE_DIR + self.files_dir + head_dic['user_name'] + '\\'
while True:
send_size = 0
files_dict = {}
for root, dirs, files in os.walk(file_path):
for f in files:
files_dict[f] = os.path.getsize(os.path.join(root, f))
files_dict_json = json.dumps(files_dict)
files_dict_json_bytes = bytes(files_dict_json, encoding=self.coding)
files_dict_json_bytes_struct = struct.pack('i', len(files_dict_json_bytes))
self.request.send(files_dict_json_bytes_struct)
is_received = self.request.recv(1024)
if is_received == b'files_dict_json_bytes_struct_received':
self.request.send(files_dict_json_bytes)
print('用户:' + head_dic['user_name'] + ' 收到上传目录文件字典!')
else:
print('客户端返回信息有误,请重试!')
break
f_name = self.request.recv(1024)
self.request.send(bytes('file_name_received', encoding=self.coding))
file_path = self.BASE_DIR + self.files_dir + head_dic['user_name'] + '\\'
is_ready_for_delete = self.request.recv(1024)
if is_ready_for_delete == b'ready_for_delete':
os.remove(file_path + str(f_name, encoding=self.coding))
self.request.send(bytes('deleted_finished', encoding=self.coding))
print(('文件:%s 删除完成!') % str(f_name, encoding=self.coding))
break
else:
print('客户端接收错误,请重试!')
break
def handle(self):
'''
handle方法
:return:
'''
while True:
user_choice = self.request.recv(1024)
if user_choice == b'1':
self.login()
print('--->这话可以删除了--->进入下一阶段功能选择!')
break
elif user_choice == b'2':
self.register()
else:
self.request.send(bytes('对不起,您的输入有误!请重新输入!', encoding=self.coding))
print('用户输入有误!')
continue
while True:
try:
head_struct = self.request.recv(4)
self.request.send(bytes('head_struct_received', encoding=self.coding))
if not head_struct:
break
head_len = struct.unpack('i', head_struct)[0]
head_json = self.request.recv(head_len).decode(self.coding)
head_dic = json.loads(head_json)
cmd = head_dic['command']
if hasattr(self, cmd):
func = getattr(self, cmd)
func(head_dic)
except Exception:
break
if __name__ == '__main__':
server_obj = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), ftpserver)
server_obj.serve_forever()
客户端
__author__ = "Elijah"
__date__ = "2017/9/14 15:48"
import hmac
import json
import os
import socket
import struct
import pickle
from tkinter.filedialog import askopenfilename, askdirectory
class ftpclient:
address_family = socket.AF_INET
socket_type = socket.SOCK_STREAM
allow_reuse_address = False
max_packet_size = 8192
coding = 'utf-8'
request_queue_size = 5
def __init__(self, server_address, connect=True):
'''
√初始化客户端
:param server_address: 服务器IP与Port信息
:param connect: 是否立即创建连接,默认选项True
'''
self.server_address = server_address
self.socket = socket.socket(self.address_family, self.socket_type)
if connect:
try:
self.client_connect()
except:
self.client_close()
raise
def client_connect(self):
'''
√客户端建立连接
:return:
'''
self.socket.connect(self.server_address)
def client_close(self):
'''
√客户端关闭连接
:return:
'''
self.socket.close()
def conn_auth(self, key):
'''
验证客户端到服务器的链接
:param conn:
:return:
'''
msg = self.socket.recv(32)
h = hmac.new(key, msg)
self.socket.send(key)
info = self.socket.recv(1024)
if info == b'received':
digest = h.digest()
self.socket.sendall(digest)
def upload(self, head_dic):
'''
上传文件
:param head_dic:
:return:
'''
while True:
head_json = json.dumps(head_dic)
head_json_bytes = bytes(head_json, encoding=self.coding)
head_struct = struct.pack('i', len(head_json_bytes))
self.socket.send(head_struct)
is_received = self.socket.recv(1024)
if is_received == b'head_struct_received':
self.socket.send(head_json_bytes)
send_size = 0
is_dirspaceok_or_continue = self.socket.recv(1024)
if is_dirspaceok_or_continue == b'file_already_exist':
is_continue = input('对不起,您选择的文件\033[4m ' + os.path.basename(
head_dic['file_name']) + ' \033[0m已经在服务端存在,是否选择断点续传(y/n)?\n>>>').strip()
if is_continue.lower() == 'y':
self.socket.send(bytes('continue_upload', encoding=self.coding))
existfile_size = self.socket.recv(1024)
with open(head_dic['file_name'], 'rb') as f:
f.seek(int(existfile_size))
for line in f:
self.socket.send(line)
send_size += len(line)
print('文件上传进度:' + str(round((send_size / 1024), 2)) + ' KB / ' + str(
round((head_dic['file_size'] / 1024), 2)) + ' KB')
print('文件 ' + os.path.basename(head_dic['file_name']) + ' 上传完成!\n')
break
else:
print('您不选择断点续传功能,请重新选择上传文件!')
break
elif is_dirspaceok_or_continue == b'Insufficient_directory_space':
self.socket.send(bytes('Insufficient_directory_space_received',encoding=self.coding))
u_space = self.socket.recv(1024)
print('对不起,您选择的文件\033[4m ' + os.path.basename(head_dic['file_name']) + ' \033[0m上传后将导致目录超过 \033[0;32m'+str(u_space,encoding=self.coding)+' MB \033[0m 配额空间,请选择删除文件功能移除目录下的文件以便可以再次上传,谢谢!\n')
break
elif is_dirspaceok_or_continue == b'Directory_space_available':
with open(head_dic['file_name'], 'rb') as f:
for line in f:
self.socket.send(line)
send_size += len(line)
print('文件上传进度:' + str(round((send_size / 1024), 2)) + ' KB / ' + str(
round((head_dic['file_size'] / 1024), 2)) + ' KB')
print('文件 ' + os.path.basename(head_dic['file_name']) + ' 上传完成!\n')
break
else:
print('对不起,服务端接收错误,请重试!')
break
else:
print('对不起,服务器端没有收到报头结构信息!')
continue
def download(self, head_dic):
'''
下载
:return:
'''
while True:
count = 0
files_list = []
head_json = json.dumps(head_dic)
head_json_bytes = bytes(head_json, encoding=self.coding)
head_struct = struct.pack('i', len(head_json_bytes))
self.socket.send(head_struct)
is_received = self.socket.recv(1024)
if is_received == b'head_struct_received':
self.socket.send(head_json_bytes)
recv_size = 0
files_dict_json_bytes_struct = self.socket.recv(4)
self.socket.send(bytes('files_dict_json_bytes_struct_received', encoding=self.coding))
if not files_dict_json_bytes_struct:
break
files_dict_json_len = struct.unpack('i', files_dict_json_bytes_struct)[0]
files_dict_json = self.socket.recv(files_dict_json_len).decode(self.coding)
files_dict = json.loads(files_dict_json)
print('用户:' + head_dic['user_name'] + '的目录为:')
for k, v in files_dict.items():
count += 1
files_list.append(k)
print(('%s 、文件:\033[4m %s \033[0m 大小:\033[1;32m %.2f \033[0m MB') % (count, k, (v / 1048576)))
user_download_choice = input('请输入要下载文件的编号:\n>>>').strip()
for i, val in enumerate(files_list):
if int(user_download_choice) == (i + 1):
download_filename = val
self.socket.send(bytes(download_filename, encoding=self.coding))
break
else:
download_filename = ''
is_filename_received = self.socket.recv(1024)
if (download_filename != '') and (is_filename_received == b'file_name_received'):
with open(os.path.join(head_dic['file_name'], os.path.basename(download_filename)),
'wb') as f_w:
while recv_size < int(files_dict[download_filename]):
recv_data = self.socket.recv(self.max_packet_size)
f_w.write(recv_data)
recv_size += len(recv_data)
print(('文件下载进度:%.2f KB / %.2f KB') % (
recv_size / 1024, (files_dict[download_filename]) / 1024))
self.socket.send(bytes('received_finished', encoding=self.coding))
print('用户:' + head_dic['user_name'] + ' 文件:' + download_filename + ' 下载完成!\n')
break
else:
print('选择的文件不存在!')
continue
else:
print('对不起,服务器端没有收到报头结构信息!')
continue
def show_dir(self, head_dic):
'''
查看用户上传目录
:return:
'''
while True:
head_json = json.dumps(head_dic)
head_json_bytes = bytes(head_json, encoding=self.coding)
head_struct = struct.pack('i', len(head_json_bytes))
self.socket.send(head_struct)
is_received = self.socket.recv(1024)
if is_received == b'head_struct_received':
self.socket.send(head_json_bytes)
files_dict_json_bytes_struct = self.socket.recv(4)
self.socket.send(bytes('files_dict_json_bytes_struct_received', encoding=self.coding))
if not files_dict_json_bytes_struct:
break
files_dict_json_len = struct.unpack('i', files_dict_json_bytes_struct)[0]
files_dict_json = self.socket.recv(files_dict_json_len).decode(self.coding)
files_dict = json.loads(files_dict_json)
print('用户:' + head_dic['user_name'] + '的上传目录为:')
for k, v in files_dict.items():
print(('文件:\033[4m %s \033[0m 大小:\033[1;32m %.2f \033[0m MB') % (k, (v / 1048576)))
break
else:
print('对不起,服务器端没有收到报头结构信息!')
continue
def delete_file(self, head_dic):
'''
删除用户目录下文件
:param head_dic:
:return:
'''
while True:
count = 0
files_list = []
head_json = json.dumps(head_dic)
head_json_bytes = bytes(head_json, encoding=self.coding)
head_struct = struct.pack('i', len(head_json_bytes))
self.socket.send(head_struct)
is_received = self.socket.recv(1024)
if is_received == b'head_struct_received':
self.socket.send(head_json_bytes)
recv_size = 0
files_dict_json_bytes_struct = self.socket.recv(4)
self.socket.send(bytes('files_dict_json_bytes_struct_received', encoding=self.coding))
if not files_dict_json_bytes_struct:
break
files_dict_json_len = struct.unpack('i', files_dict_json_bytes_struct)[0]
files_dict_json = self.socket.recv(files_dict_json_len).decode(self.coding)
files_dict = json.loads(files_dict_json)
print('用户:' + head_dic['user_name'] + '的目录为:')
for k, v in files_dict.items():
count += 1
files_list.append(k)
print(('%s 、文件:\033[4m %s \033[0m 大小:\033[1;32m %.2f \033[0m MB') % (count, k, (v / 1048576)))
user_delete_choice = input('请输入要\033[1;31m删除\033[0m文件的编号:\n>>>').strip()
for i, val in enumerate(files_list):
if int(user_delete_choice) == (i + 1):
delete_filename = val
self.socket.send(bytes(delete_filename, encoding=self.coding))
break
else:
delete_filename = ''
is_filename_received = self.socket.recv(1024)
if (delete_filename != '') and (is_filename_received == b'file_name_received'):
self.socket.send(bytes('ready_for_delete', encoding=self.coding))
is_finished = self.socket.recv(1024)
if is_finished == b'deleted_finished':
print('用户:' + head_dic['user_name'] + ' 文件:\033[4m ' + delete_filename + ' \033[0m删除完成!\n')
break
else:
print('对不起,删除文件出错,请重试!')
break
else:
print('选择的文件不存在或删除失败,请重试!')
continue
else:
print('对不起,服务器端没有收到报头结构信息!')
continue
def user_exit(self, head_dic):
print('用户:' + head_dic['user_name'] + '退出!')
exit()
def operation(self):
'''
用户执行功能
:return:
'''
u_space = 0
end_loop = True
while end_loop:
input_choice = input('您好,请输入您要选择功能的对应编号:\n1、登陆\n2、注册\n3、退出\n>>>').strip()
if input_choice == '1':
self.socket.send(input_choice.encode(self.coding))
while True:
user_name = input('你好,请输入用户名(或者输入q退出):\n>>>').strip()
self.socket.send(user_name.encode(self.coding))
data_username = self.socket.recv(1024)
if data_username == b'user_name quit':
print('用户退出登陆程序!')
break
elif data_username == b'user_name available':
user_password = input('欢迎你!' + user_name + '请输入密码(或者输入q退出):\n>>>').strip()
self.socket.send(user_password.encode(self.coding))
data_password = self.socket.recv(1024)
if data_password == b'user_password quit':
print('用户退出登陆程序!')
break
elif data_password == b'password available':
self.socket.send(bytes('get password available', encoding=self.coding))
print('密码正确!进行客户端验证!')
data_key = self.socket.recv(1024)
print('接收到从服务端发来的验证码 ' + str(data_key, encoding=self.coding) + ' 正在进行验证....')
self.conn_auth(data_key)
data_authresult = self.socket.recv(1024)
if data_authresult == b'auth_successful':
print('客户端验证成功!进入下一阶段功能选择!')
end_loop = False
break
elif data_authresult == b'auth_failed':
print('验证失败,请重新进行登录操作!谢谢!')
continue
elif data_password == b'password wrong':
print('对不起,您输入的密码有误,请重新输入!')
continue
else:
print('对不起,您的输入有误,请重新输入!')
continue
elif data_username == b'user_name wrong':
print('对不起,您输入的用户名有误!')
continue
elif input_choice == '2':
self.socket.send(input_choice.encode(self.coding))
while True:
new_user = input('你好,请输入要注册的用户名(或者输入q退出):\n>>>').strip()
self.socket.send(new_user.encode(self.coding))
data = self.socket.recv(1024)
if data == b'user exist':
print('对不起,您输入的用户名已经被注册,请重新输入!')
continue
elif data == b'user available':
new_password = input('用户名有效,请输入密码!(或者输入q退出)\n>>>').strip()
self.socket.send(new_password.encode(self.coding))
is_received = self.socket.recv(1024)
if is_received == b'password_received':
user_space = input('请输入用户上传目录的空间配额!(或者输入q退出):\n(默认10MB)>>>').strip()
self.socket.send(bytes(user_space, encoding=self.coding))
data = self.socket.recv(1024)
if data == b'Register Successful':
print('用户' + new_user + '注册成功! 密码为:' + new_password + ' 用户上传目录空间为:' + user_space + 'MB')
u_space = user_space
break
else:
print('对不起,注册失败,请重新注册!')
continue
else:
print('对不起,服务端接收密码有误,请重新注册!')
continue
elif data == b'user quit':
print('用户退出注册功能!')
break
elif input_choice == '3':
print('欢迎下次使用!')
exit()
else:
print('对不起,您输入的功能编号有误,请重新输入!')
continue
end_func = True
choice_dict = {'1': 'upload', '2': 'download', '3': 'show_dir', '4': 'delete_file', '5': 'user_exit', }
while end_func:
func_choice = input('用户:' + user_name + ' 请选择功能:\n1、上传文件\n2、下载文件\n3、查看目录\n4、删除文件\n5、退出\n>>>:').strip()
user_command = choice_dict[func_choice]
if (func_choice == '1'):
file_name = askopenfilename(filetypes=(("All files", "*.*"),))
file_size = os.path.getsize(file_name)
head_dic = {'command': user_command, 'file_name': file_name, 'file_size': file_size,
'user_name': user_name}
elif func_choice == '2':
file_name = askdirectory(title='选择下载至目录')
file_size = ''
head_dic = {'command': user_command, 'file_name': file_name, 'file_size': file_size,
'user_name': user_name}
else:
file_name = ''
file_size = ''
head_dic = {'command': user_command, 'file_name': file_name, 'file_size': file_size,
'user_name': user_name}
if hasattr(self, user_command):
func = getattr(self, user_command)
func(head_dic)
if __name__ == '__main__':
client = ftpclient(('127.0.0.1', 8080))
client.operation()