要求:

1. 用户加密认证

2. 多用户同时登陆

3. 每个用户有自己的家目录且只能访问自己的家目录

4. 对用户进行磁盘配额、不同用户配额可不同

5. 用户可以登陆server后,可切换目录

6. 查看当前目录下文件

7. 上传下载文件,保证文件一致性

8. 传输过程中现实进度条

9. 支持断点续传

路径如下

代码

import socket
import pickle
import hashlib
import sys
import time
import os
A = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
class Ftp_client(object):
def __init__(self):
self.client = socket.socket()
def help(self):
'''
帮助说明
:return:
'''
print('''请输入正确的指令:
ls: 查看根目录下文件
cd: 切换目录
download: 下载文件
upload:上文件
mkdir:新建立文件夹
''')
def connet(self, ip, port):
'''
链接服务器
:param ip:
:param port:
:return:
'''
self.client.connect((ip, port))
data = self.client.recv(1024)
print(data.decode())
self.main()
self.ftp_main()
def login(self):
'''
登录
:return:
'''
name = input('请输入姓名').lower()
password = input('请输入密码')
dict = {'name': name, 'password': password}
self.client.sendall(pickle.dumps(dict))
data = self.client.recv(1024)
print(data.decode())
if data.decode()=='输入有误':
return False
def register(self):
'''
注册
:return:
'''
while True:
a = input('请输入注册哪种用户: 1: 普通用户(可用空间10M), 2: VIP用户(可用30M)')
if a =='':
space = 10485760
break
elif a== '':
space = 31457280
break
else:
print('输入有误')
continue
name = input('请输入姓名').lower()
pd = input('请输入密码')
dict = {'name': name, 'password': pd, 'space': space}
self.client.sendall(pickle.dumps(dict))
data = self.client.recv(1024)
print(data.decode())
if data.decode()== '用户名已存在,请重新输入':
return False def main(self):
while True:
a = input('请输入 1. 用户登录 2. 用户注册 3.退出')
if a == '':
self.client.sendall('login'.encode())
res = self.login()
elif a == '':
self.client.sendall('register'.encode())
res = self.register()
elif a == '':
exit()
else:
print('输入有误')
continue
if res is False:
continue
else:
break def download(self):
'''
下载
:return:
'''
while True:
data = self.client.recv(1024)
choose = input('文件所在路径 1 根目录 2 子目录')
if choose == '':
path = ''
break
elif choose =='':
path = input('请输入路径,子路径用 / 分隔隔开') # 根目录不用输入
break
else:
print('输入有误')
continue
self.client.sendall(path.encode())
data = self.client.recv(1024)
filename = input('请输入下载文件名')
self.client.sendall(filename.encode())
size = self.client.recv(1024).decode()
if size == '该文件不存在':
print ('该文件不存在')
return False
else:
size = int(size)
if os.path.exists(os.path.join(A, 'db', filename)):
r_size = int(os.path.getsize(os.path.join(A, 'db', filename)))#存在文件的size
while True:
choose = input('文件已存在, 1 重新下载 2 停止下载 3 新起名再下载 4 继续下载')
if choose == '':
dic={}
dic['choose'] = choose
self.client.sendall(pickle.dumps(dic))
return False
elif choose == '':
f = open(os.path.join(A, 'db',filename),'wb')
r_size = 0
break
elif choose == '':
name = input('请输入新文件名')
f = open(os.path.join(A, 'db',name),'wb')
r_size = 0
break
elif choose == '':
f = open(os.path.join(A, 'db',filename),'ab')
break
else:
print('输入有误,请重新输入')
dic={}
dic['choose'] = choose
dic['size'] = r_size
self.client.sendall(pickle.dumps(dic))
else:
r_size = 0
f = open(os.path.join(A, 'db', filename),'xb') if size == 0:
f.close()
print('接收完成')
else:
while r_size < size:
file = self.client.recv(1024)
f.write(file)
f.flush() #文件强行写入file,预防中途中断
r_size += len(file)
view_bar(r_size, size)
time.sleep(0.1)
else:
print('接收完成')
f.close() def upload(self):
filename = input('请输入上传的文件名')
if os.path.exists(os.path.join(A, 'db', filename)):
size = os.path.getsize(os.path.join(A, 'db', filename)) #文件size
path = input('请输入上传的路径,子路径用 / 分隔隔开, h为根目录')
dic = {}
dic['filename'] = filename
dic['size'] = size
dic['path'] = path
self.client.sendall(pickle.dumps(dic))
f = open(os.path.join(A, 'db', filename), 'rb')
else:
print ('此文件不存在')
return False
data = self.client.recv(1024)
ls = pickle.loads(data) #ls[2]: ;
if ls[-1]=='': #ls[-1]:检查下载的路径是否存在
print ('此路径不存在')
return False
if ls[0] == '':#ls[0]:检查空间够不够;
print ('空间不足,不能上传') else:
if ls[1] == '': #ls[1]:检查下载是否存在
while True:
a = input('文件已存在, 1 重新下载 2 停止下载 3 新起名再下载 4 继续下载')
f_ls = []
f_ls.append(a)
if a == '':
break
elif a == '':
return False
elif a =='':
f_name = input('请输入新文件名')
f_ls.append(f_name)
break
elif a=='':
l_size = ls[2] #ls[2]:已下载的文件大小
f.seek(l_size) #把指针放到已下载的地方,继续下载
break
else:
print ('输入有误')
else:
f_ls = []
f_ls.append('') # 5:下载文件不存在
self.client.sendall(pickle.dumps(f_ls))
data = self.client.recv(1024).decode()
print (data)
for line in f:
self.client.sendall(line)
num = f.tell() #查看文件上传位置
view_bar(num, size)
time.sleep(0.1)
f.close()
print ('接收完成')
return False def ls(self):
data = self.client.recv(1024)
if data ==''.encode():
print('此目录为空')
elif data ==''.encode():
print('此文件不存在')
else:
ls = pickle.loads(data)
print('此文件里有:')
for i in ls:
print(i) def mkdir(self):
name = input('请输入文件夹名')
self.client.sendall(name.encode())
data = self.client.recv(1024).decode()
print(data) def cd(self):
name = input('请输入路径,子路径用 / 分隔隔开') # 根目录不用输入
self.client.sendall(name.encode())
path = self.client.recv(1024).decode() if path == '':
print ('此目录不存在')
return False
else:
print ('所在文件夹路径为 %s' % path)
self.client.sendall('ok'.encode())
data = self.client.recv(1024)
if data ==''.encode():
print('此目录为空')
else:
ls = pickle.loads(data)
print('此文件里有:')
for i in ls:
print(i) def ftp_main(self):
while True:
a = input('请输入相应的指令, help:查询, exit:退出')
if hasattr(self, a):
self.client.sendall(a.encode())
func = getattr(self, a)
func()
elif a == 'exit':
exit()
else:
self.help()
continue def view_bar(num, total):
'''进度条'''
rate = float(num) / float(total)
rate_num = int(rate * 100)
r = '\r%d%%' % (rate_num, ) #\r 回到到开头
sys.stdout.write(r)
sys.stdout.flush() #删除记录 ftp = Ftp_client()
ftp.connet('localhost', 9999)

client

import socketserver
import pickle
import os
import time
A = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
class MyTCPHandler(socketserver.BaseRequestHandler):
def handle(self):
while True:
try:
self.request.sendall('链接成功'.encode())
while True:
data = self.request.recv(1024).decode()
if data =='login':
a = self.login()
else:
a = self.register() #a为 list,[0]是name,[1]是可用空间
if a is False:
continue
else:
while True:
data = self.request.recv(1024)
func = getattr(self, data.decode())
func(a)
except Exception: #检查客户端是否连接正常
print('客户端断开')
break def login(self):
db_dict = pickle.load(open(os.path.join(A, 'db', 'register'),'rb'))
self.data = self.request.recv(1024)
dict = pickle.loads(self.data)
if dict['name'] in db_dict:
if dict['password']==db_dict[dict['name']][0]:
self.request.sendall('登录成功'.encode())
return [dict['name'], db_dict[dict['name']][1]] #返回用户名,用户可用空间
else:
self.request.sendall('输入有误'.encode())
return False
else:
self.request.sendall('输入有误'.encode())
return False
def register(self):
dict = pickle.loads(self.request.recv(1024))
print (dict)
if os.path.exists(os.path.join(A, 'db', dict['name'])):
self.request.sendall('用户名已存在,请重新输入'.encode())
return False
else:
self.request.sendall('注册成功'.encode())
os.makedirs(os.path.join(A, 'db', dict['name']))
# n_dict ={}
n_dict = pickle.load(open(os.path.join(A, 'db', 'register'), 'rb'))
print (1)
print (n_dict)
n_dict[dict['name']]=[dict['password'],int(dict['space'])] #存储格式为{姓名:[密码,可用空间大少]}
print (n_dict)
pickle.dump(n_dict,open(os.path.join(A, 'db', 'register'), 'wb'))
return [dict['name'], int(dict['space'])]
def help(self, a):
return False
def upload(self, list):
name = list[0]
b_path = os.path.join(A, 'db', name) #自己的根目录
h_size = int(list[1]) #自己可用的空间大小
data = self.request.recv(1024)
dic = pickle.loads(data)
f_size = int(dic['size']) #上传文件大小
filename = dic['filename']
path = dic['path']
s_ls = []
if h_size < f_size:
a = '' #空间不足
s_ls.append(a)
else:
a = ''
s_ls.append(a)
if path=='h': #存在根目录
l_path =os.path.join(b_path,filename)
else:
res = path.split('/')
print (res)
for i in res:
b_path = os.path.join(b_path, i) #合拼成子目录
l_path = os.path.join(b_path,filename) #文件路径 if os.path.exists(l_path):
b = '' #文件已存在
file_size = os.path.getsize(l_path)
s_ls.append(b)
s_ls.append(file_size)
else:
b = ''
s_ls.append(b)
if os.path.exists(b_path):
c = ''
else:
c=''#文件夹不存在,可以结束
s_ls.append(c)
self.request.sendall(pickle.dumps(s_ls))
return False
s_ls.append(c)
self.request.sendall(pickle.dumps(s_ls))
f_ls = pickle.loads(self.request.recv(1024))#文件以什么方式打开
self.request.sendall('准备开始'.encode())
if f_ls[0] =='':
f = open(l_path,'wb')
file_size = 0
elif f_ls[0]=='':
return False
elif f_ls[0]=='':#文件名另起
filename = f_ls[1]
l_path = os.path.join(b_path,filename)
f = open(l_path,'wb')
file_size = 0
elif f_ls[0]=='':
f = open(l_path,'ab')
else:
f = open(l_path,'xb')
file_size = 0
if f_size == 0:
f.close()
return False
else:
while file_size< f_size:
line = self.request.recv(1024)
f.write(line)
f.flush()
file_size += len(line)
else:
f.close()
l_dict = pickle.load(open(os.path.join(A, 'db', 'register'), 'rb'))
l_dict[name][1] = h_size - f_size #修改已用空间
pickle.dump(l_dict, open(os.path.join(A, 'db', 'register'), 'wb'))
return False def download(self, list):
self.request.sendall('ok'.encode())
path = self.request.recv(1024).decode() #检查文件存在子目录或根目录
self.request.sendall('check'.encode())
filename = self.request.recv(1024).decode()
name = list[0]
if path == '':
l_path = os.path.join(A, 'db', name,filename)
else:
data = path.split('/')
pathname = os.path.join(A, 'db', name)
for i in data:
pathname = os.path.join(pathname, i) #合拼子目录
l_path = os.path.join(pathname,filename)
print (l_path)
if os.path.exists(l_path):
f = open(l_path, 'rb')
size = os.path.getsize(l_path) #检查文件
self.request.sendall(str(size).encode()) #要以字符串格式传数字
data = self.request.recv(1024)
dic = pickle.loads(data)
if dic['choose']=='':
return False
elif dic['choose']=='':
f.seek(int(dic['size'])) #把指针定位到已下载的地方
for line in f:
self.request.sendall(line)
f.close()
print ('done')
else:
self.request.sendall('该文件不存在'.encode()) def ls(self, list):
name = list[0]
ls = os.listdir(os.path.join(A, 'db', name))
if len(ls)==0:
self.request.sendall(''.encode())
else:
a = []
for i in ls:
a.append(i) #把存在的文件放入list
self.request.sendall(pickle.dumps(a))
def cd(self, list):
data = self.request.recv(1024).decode()
name = list[0]
path = os.path.join(A, 'db', name) #根目录
path_ls = data.split('/')
for i in path_ls:
path = os.path.join(path, i) #合拼子目录
print (path)
if os.path.exists(path) is False:
print (1)
path = ''
self.request.sendall(path.encode())
return False
ls = os.listdir(path)
self.request.sendall(path.encode())
data = self.request.recv(1024)
if len(ls)==0:
self.request.sendall(''.encode())
else:
a = []
for i in ls:
a.append(i)
self.request.sendall(pickle.dumps(a)) def mkdir(self, a):
filename = self.request.recv(1024).decode()
name = a[0]
if os.path.exists(os.path.join(A, 'db', name,filename)): #检查路径是否存在
self.request.sendall('文件夹已存在'.encode())
else:
os.makedirs(os.path.join(A, 'db', name, filename))
self.request.sendall('已建好'.encode()) host, port = 'localhost', 9999
server = socketserver.ThreadingTCPServer((host, port), MyTCPHandler)
server.serve_forever()

server

高级FTP服务器开发的更多相关文章

  1. Python09作业思路及源码:高级FTP服务器开发(仅供参考)

    高级FTP服务器开发 一,作业要求 高级FTP服务器开发 用户加密认证(完成) 多用户同时登陆(完成) 每个用户有不同家目录且只能访问自己的家目录(完成) 对用户进行磁盘配额,不同用户配额可不同(完成 ...

  2. python第四十八天--高级FTP

    高级FTP服务器1. 用户加密认证2. 多用户同时登陆3. 每个用户有自己的家目录且只能访问自己的家目录4. 对用户进行磁盘配额.不同用户配额可不同5. 用户可以登陆server后,可切换目录6. 查 ...

  3. (转)python高级FTP

    原文地址:http://www.itnose.net/detail/6754889.html高级FTP服务器1. 用户加密认证2. 多用户同时登陆3. 每个用户有自己的家目录且只能访问自己的家目录4. ...

  4. 实用程序Commer的开发——U盘内容可选同步至FTP服务器

    需求分析:需要在软件运行后将插入的U盘里面的文件Copy至本机上,然后可选的上传一部分至FTP服务器上. 系统设计:基于MFC的基本对话框程序:主要模块有检测U盘插入并复制文件以及上传到网络.通过对U ...

  5. 基于线程开发一个FTP服务器

    一,项目题目:基于线程开发一个FTP服务器 二,项目要求: 基本要求: 1.用户加密认证   2.允许同时多用户登录   3.每个用户有自己的家目录 ,且只能访问自己的家目录   4.对用户进行磁盘配 ...

  6. python开发ftp服务器第一天(pyftpdlib)

    学习了大约快一个月的python,现在开始有意识做一些项目.(我的新书<Python爬虫开发与项目实战>出版了,大家可以看一下样章) 据我了解,python现在更多的是用于自动化运维方面, ...

  7. FTP服务器高级配置

    设置FTP服务器的访问限制 /etc/vsftpd/ftpusers ftpusers :黑名单 其内所有的用户无法登录FTP服务器 如果userlist_enable=YES(主配置文件中设置),u ...

  8. python作业高级FTP

    转载自:https://www.cnblogs.com/sean-yao/p/7882638.html 作业需求: 1. 用户加密认证 2. 多用户同时登陆 3. 每个用户有自己的家目录且只能访问自己 ...

  9. python作业高级FTP(第八周)

    作业需求: 1. 用户加密认证 2. 多用户同时登陆 3. 每个用户有自己的家目录且只能访问自己的家目录 4. 对用户进行磁盘配额.不同用户配额可不同 5. 用户可以登陆server后,可切换目录 6 ...

随机推荐

  1. 20190422 SQL SERVER 服务

    -- 数据库服务-- SQL Server(MSSQLSERVER)是必须要开启的,这个是数据库引擎服务,就像汽车的发动机一样-- SQL Server代理(MSSQLSERVER)是代理服务,比如你 ...

  2. java框架之SpringBoot(15)-安全及整合SpringSecurity

    SpringSecurity介绍 Spring Security 是针对 Spring 项目的安全框架,也是 Spring Boot 底层安全模块默认的技术选型.它可以实现强大的 Web 安全控制.对 ...

  3. laravel----------php7.0.12 laravel 链接sqlserver数据库

    https://www.microsoft.com/en-us/download/details.aspx?id=20098 下载最后一个,然后这个工具可以将dll扩展下载下来,选择一个空白的文件夹就 ...

  4. C# 获取 mp3文件信息【包括:文件大小、歌曲长度、歌手、专辑】

    C# 获取 mp3文件信息[包括:文件大小.歌曲长度.歌手.专辑] 第一种方式:[代码已验证] // http://bbs.csdn.net/topics/390392612   string fil ...

  5. JavaWeb-----ServletConfig对象和servletContext对象

    1.ServletConfig ServletConfig:代表当前Servlet在web.xml中的配置信息 String getServletName()  -- 获取当前Servlet在web. ...

  6. Rest和Restful & http

    Rest :Representational State Transfer 表述性状态转移 Restful: Rest+ful形容词,遵循Rest原则的应用程序或设计 Rest原则: 1. 网络上的所 ...

  7. vscode格式化代码插件Beautify

    vscode格式化代码安装 VsCode 格式化代码插件搜索并安装 Beautify 格式化代码插件使用:打开要格式化的文件 —> F1 —> Beautify file —> 选择 ...

  8. 教你如何在win7中安装cygwin64

    首先,说说我们为什么要安装cygwin吧,长期在win7下开发的人员可能不习惯使用unix系统,但由于工作问题,你又被逼要在unix环境下开发,那该如何是好啊?但现在你不用再纠结了,因为有cygwin ...

  9. Python 面向对象介绍

    面向对象,面向过程 面向对象引子 人狗大战,人与狗都有不同的特点,如果要写出这两个不同角色 需要写出两个角色,可以使用嵌套函数,函数内在写入函数,然后通 过字典,将里层函数reture出来,在调用. ...

  10. VMware安装步骤既常见问题

    一.vmware出问题? 可以使用vmvare的修复功能. 二.创建虚拟机 1)第一步:选择自定义下一步,典型里是都设定好了的. 2)第二步:选择12默认下一步 3)第三步:可以从光驱中安装,可以从文 ...