模拟百度云盘版的ftp
思路:
一、分两个大的文件夹,一个是客户端,一个服务端的
二、实现的功能
1. 登陆--对用户名的合法性进行检测(实验账户:alex,123)
注册--设置账户,其中网盘列表设置为空,刚注册的用户给到50下载豆
规则:
用户上传文件是上传到服务端的共享文件库里,同时会添加到自己的网盘里,
上传一个文件就可以奖励50下载豆,并自己上传的文件以后下载不用下载豆
用户去找资源,其实就是把服务端的共享文件库陈列给客户看,客户如果把
服务端的资源文件添加到自己的网盘,必须消耗20下载豆
用户下载不用消耗下载豆,但是只能从自己的网盘里下载
2.进入到FTP客户可以选择:
上传--
遍历自己本地文件库,选择上传,上传过程中显示进度条(支持断点续传)
下载--
遍历自己的网盘,选择下载,下载过程中显示进度条(支持断点下载)
找资源--
遍历服务端的共享文件库,选择添加到自己的网盘
查看我的网盘--
遍历自己的网盘展示
流程图
代码实现
目录:
client端:
client_main.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | import os import sys pat = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(pat) from config import Config import socket import time import json def main(): #连接服务器 ip_port = ( '127.0.0.1' , 8009 ) sk = socket.socket() sk.connect(ip_port) #接收欢迎信息 bt = sk.recv( 1024 ) print ( str (bt,encoding = 'utf-8' )) flag1 = 1 while flag1: # 让客户选择操作 print ( '\t1\t登陆\n\t2\t注册' ) choose = input ( '请选择序号选择你的操作:' ) if choose = = '2' : sk.sendall(bytes(choose,encoding = 'utf-8' )) print ( '注册页面!' ) while True : reg_usr = input ( '请输入注册用户名:' ) sk.sendall(bytes(reg_usr,encoding = 'utf-8' )) ret = str (sk.recv( 1024 ),encoding = 'utf-8' ) if ret = = '合法' : reg_pwd = input ( '请输入注册密码:' ) sk.sendall(bytes(reg_pwd,encoding = 'utf-8' )) bt = sk.recv( 1024 ) print ( str (bt,encoding = 'utf-8' )) break else : print (ret) elif choose = = '1' : sk.sendall(bytes(choose, encoding = 'utf-8' )) print ( '登陆页面!' ) flag2 = 1 while flag2: landed_usr = input ( '请输入用户名:' ) sk.sendall(bytes(landed_usr,encoding = 'utf-8' )) ret = str (sk.recv( 1024 ), encoding = 'utf-8' ) if ret = = '存在' : while True : landed_pwd = input ( '请输入密码:' ) sk.sendall(bytes(landed_pwd,encoding = 'utf-8' )) bt = sk.recv( 1024 ) if str (bt,encoding = 'utf-8' ) = = 'yes' : print ( '登陆成功!' ) flag1 = 0 flag2 = 0 enter_flag = 1 break else : print ( str (bt, encoding = 'utf-8' )) else : print ( '用户名不存在!请重新输入!' ) else : print ( '输入有误!请重新输入!' ) #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ while enter_flag: print ( '\n\t1\t上传\n' '\t2\t下载\n' '\t3\t找资源\n' '\t4\t查看我的网盘\n' ) choose = input ( '请选择你接下来的操作(输入q退出):' ) #把客户的选择发过去 sk.sendall(bytes(choose, encoding = 'utf-8' )) if choose = = '1' : #遍历本地文件,并让客户选择 for k,file_name in enumerate (Config.local_file_list, 1 ): print (k,file_name) m = input ( '请选择你要上传的文件:' ) file_name = Config.local_file_list[ int (m) - 1 ] print (file_name) #把文件名发过去 sk.sendall(bytes(file_name,encoding = 'utf-8' )) print ( '文件名已发过去!' ) #接收检测的文件大小 file_size = str (sk.recv( 1024 ),encoding = 'utf-8' ) print ( '文件大小已收到!' ,file_size) file_name_path = os.path.join(Config.PATH,file_name) all_size = os.stat(file_name_path).st_size print ( '总大小:' ,all_size) if all_size ! = int (file_size): with open (file_name_path, 'rb' ) as f: num = int (file_size) f.seek(num) for line in f: sk.sendall(line) file_size = str (sk.recv( 1024 ),encoding = 'utf-8' ) sys.stdout.write( '\r' ) # 每一次清空原行 sys.stdout.write( '%s%% |%s' % ( int ( int (file_size) / all_size * 100 ), int ( int (file_size) / all_size / 2 * 100 ) * '*' )) sys.stdout.flush() # 强制刷新缓冲区 time.sleep( 0.3 ) sk.sendall(bytes( '1' ,encoding = 'utf-8' )) print ( '\n上传完毕!' ) else : print ( '你要上传的文件已存在!' ) elif choose = = '2' : s = str (sk.recv( 1024 ), encoding = 'utf-8' ) my_wangpan = json.loads(s) print ( '我的网盘:' ) for n, file_na in enumerate (my_wangpan, 1 ): print (n, file_na) load_choose = input ( '请输入序号选择你要下载的文件:' ) sk.sendall(bytes(load_choose,encoding = 'utf-8' )) all_size = str (sk.recv( 1024 ),encoding = 'utf-8' ) print ( type (all_size),all_size) load_file_name = my_wangpan[ int (load_choose) - 1 ] pth = os.path.join(Config.PATH, load_file_name) if load_file_name in Config.local_file_list: file_size = os.stat(pth).st_size if str (file_size) = = all_size: sk.sendall(bytes( '下载过' ,encoding = 'utf-8' )) sk.recv( 1024 ) print ( '你本地文件里已有要下载的文件!' ) else : print ( '继续下载...' ) sk.sendall(bytes( '下载了一点点' ,encoding = 'utf-8' )) sk.recv( 1024 ) sk.sendall(bytes( str (file_size),encoding = 'utf-8' )) with open (pth, 'ab' ) as f: while True : bt = sk.recv( 1024 ) if int (file_size / int (all_size)) = = 1 : break else : f.write(bt) file_size + = len (bt) sys.stdout.write( '\r' ) # 每一次清空原行 sys.stdout.write( '%s%% |%s' % ( int (file_size / int (all_size) * 100 ), int (file_size / int (all_size) / 2 * 100 ) * '*' )) sys.stdout.flush() # 强制刷新缓冲区 time.sleep( 0.3 ) print ( '\n下载完成!' ) else : print ( '开始下载...' ) sk.sendall(bytes( '没下载' ,encoding = 'utf-8' )) sk.recv( 1024 ) file_size = 0 sk.sendall(bytes( '0' ,encoding = 'utf-8' )) with open (pth, 'wb' ) as f: while True : bt = sk.recv( 1024 ) if int (file_size / int (all_size)) = = 1 : break else : f.write(bt) file_size + = len (bt) sys.stdout.write( '\r' ) # 每一次清空原行 sys.stdout.write( '%s%% |%s' % ( int (file_size / int (all_size) * 100 ), int (file_size / int (all_size) / 2 * 100 ) * '*' )) sys.stdout.flush() # 强制刷新缓冲区 time.sleep( 0.3 ) print ( '下载完成!' ) elif choose = = '3' : print ( '进入!' ) s = str (sk.recv( 1024 ),encoding = 'utf-8' ) print ( '收到json字符' ) li = json.loads(s) print ( '资源如下:' ) for m,file_name in enumerate (li, 1 ): print (m,file_name) choose = input ( '请选择序号决定你想要添加到网盘的文件(添加一个文件减少20下载豆):' ) sk.sendall(bytes(choose,encoding = 'utf-8' )) print ( str (sk.recv( 1024 ),encoding = 'utf-8' )) elif choose = = '4' : s = str (sk.recv( 1024 ),encoding = 'utf-8' ) my_wangpan = json.loads(s) print ( '我的网盘:' ) for n,file_na in enumerate (my_wangpan, 1 ): print (n,file_na) elif choose.lower() = = 'q' : exit() else : print ( '你输入有误!请重新输入!' ) if __name__ = = '__main__' : main() |
config.py
1 2 3 4 5 6 7 | import os import sys pat = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) PATH = os.path.join(pat, 'db' ) local_file_list = os.listdir(PATH) |
server端
server_main.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | import os import sys pat = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(pat) from lib import account from config import Config import socketserver import json import time import pickle class MyServer(socketserver.BaseRequestHandler): def handle( self ): # print self.request,self.client_address,self.server conn = self .request conn.sendall(bytes( '欢迎来到百度云盘!' ,encoding = 'utf-8' )) flag1 = 1 while flag1: choose = str (conn.recv( 1024 ), encoding = 'utf-8' ) if choose = = '2' : while True : reg_usr = str (conn.recv( 1024 ),encoding = 'utf-8' ) ret = account.usr_ver(reg_usr) conn.sendall(bytes(ret,encoding = 'utf-8' )) if ret = = '合法' : reg_pwd = str (conn.recv( 1024 ),encoding = 'utf-8' ) hash_pwd = account.encrypt(reg_pwd) ob = account.Account() ob.registered(reg_usr,hash_pwd) account.info_add(ob) conn.sendall(bytes( '注册成功!' ,encoding = 'utf-8' )) break elif choose = = '1' : flag2 = 1 while flag2: landed_usr = str (conn.recv( 1024 ),encoding = 'utf-8' ) ret = account.land_usr_ver(landed_usr) conn.sendall(bytes(ret,encoding = 'utf-8' )) if ret = = '存在' : while True : landed_pwd = str (conn.recv( 1024 ),encoding = 'utf-8' ) obj = account.landed_ver(landed_usr,landed_pwd) if isinstance (obj,account.Account): conn.sendall(bytes( 'yes' , encoding = 'utf-8' )) flag1 = 0 flag2 = 0 break else : conn.sendall(bytes(obj, encoding = 'utf-8' )) ######################################################################################### while True : #接收客户的操作选择 choose = str (conn.recv( 1024 ),encoding = 'utf-8' ) if choose = = '1' : #接收客户发来需要上传的文件名 file_name = str (conn.recv( 1024 ),encoding = 'utf-8' ) pat = os.path.join(Config.PATH,file_name) #判断上传的文件是否存在 if file_name in Config.shared_file_list: file_size = os.stat(pat).st_size #对存在的文件,检测大小,把值传过去 conn.sendall(bytes( str (file_size),encoding = 'utf-8' )) with open (pat, 'ab' ) as f: flag = 1 while flag: bt = conn.recv( 1024 ) if len (bt) = = 1 and bt = = bytes( '1' ,encoding = 'utf-8' ): flag = 0 else : f.write(bt) file_size + = len (bt) conn.sendall(bytes( str (file_size), encoding = 'utf-8' )) obj.netdisc.append(file_name) obj.download_beans + = 50 else : conn.sendall(bytes( '0' ,encoding = 'utf-8' )) file_size = 0 with open (pat, 'wb' ) as f: flag = 1 while flag: bt = conn.recv( 1024 ) if len (bt) = = 1 and bt = = bytes( '1' , encoding = 'utf-8' ): flag = 0 else : f.write(bt) file_size + = len (bt) conn.sendall(bytes( str (file_size), encoding = 'utf-8' )) obj.netdisc.append(file_name) obj.download_beans + = 50 elif choose = = '2' : s = json.dumps(obj.netdisc) conn.sendall(bytes(s, encoding = 'utf-8' )) load_choose = str (conn.recv( 1024 ),encoding = 'utf-8' ) index_num = int (load_choose) - 1 download_file_name = obj.netdisc[index_num] pat = os.path.join(Config.PATH,download_file_name) all_size = os.stat(pat).st_size print ( type (all_size),all_size) conn.sendall(bytes( str (all_size),encoding = 'utf-8' )) if str (conn.recv( 1024 ),encoding = 'utf-8' ) ! = '下载过' : conn.sendall(bytes( '知道' ,encoding = 'utf-8' )) seek_num = int ( str (conn.recv( 1024 ),encoding = 'utf-8' )) with open (pat, 'rb' ) as f: f.seek(seek_num) for line in f: conn.sendall(line) time.sleep( 3 ) conn.sendall(bytes( '0' ,encoding = 'utf-8' )) else : conn.sendall(bytes( '知道' , encoding = 'utf-8' )) elif choose = = '3' : print ( '进入!' ) s = json.dumps(Config.shared_file_list) conn.sendall(bytes(s,encoding = 'utf-8' )) print ( '已发出json格式信息' ) #收到客户选择信息 choose = str (conn.recv( 1024 ),encoding = 'utf-8' ) index_num = int (choose) - 1 index_file_name = Config.shared_file_list[index_num] print (index_file_name) if obj.download_beans > = 20 : obj.netdisc.append(index_file_name) obj.download_beans - = 20 conn.sendall(bytes( '添加成功' ,encoding = 'utf-8' )) else : conn.sendall(bytes( '下载豆不足!添加失败!' ,encoding = 'utf-8' )) elif choose.lower() = = 'q' : with open (Config.ACCOUNT_INFO_PATH, 'rb' ) as f: li = pickle.loads(f.read()) lis = [] for i in li: if i.username = = obj.username: lis.append(obj) else : lis.append(i) with open (Config.ACCOUNT_INFO_PATH, 'wb' ) as f: f.write(pickle.dumps(lis)) elif choose = = '4' : s = json.dumps(obj.netdisc) conn.sendall(bytes(s,encoding = 'utf-8' )) if __name__ = = '__main__' : server = socketserver.ThreadingTCPServer(( '127.0.0.1' , 8009 ),MyServer) server.serve_forever() |
config.py
1 2 3 4 5 6 7 8 9 | import os import sys pat = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(pat) ACCOUNT_INFO_PATH = os.path.join(pat, 'db' , '用户信息.log' ) PATH = os.path.join(pat, 'db' , '共享文件' ) shared_file_list = os.listdir(PATH) |
account.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | import os import sys pat = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(pat) from config import Config import pickle import hashlib class Account: def __init__( self ): self .username = None self .password = None self .download_beans = 0 self .netdisc = [] def registered( self ,usr,pwd): self .username = usr self .password = pwd self .download_beans = 50 def usr_ver(usr): ''' 注册时验证用户名存不存在 :param usr: 需要验证用户名 :return: 存在--返回用户名已存在,不存在--返回合法 ''' if os.path.exists(Config.ACCOUNT_INFO_PATH): with open (Config.ACCOUNT_INFO_PATH, 'rb' ) as f: li = pickle.load(f) for i in li: if i.username = = usr: return '用户名已存在!请重新输入!' return '合法' else : return '合法' def encrypt(pwd): ''' 給密码加密的 :param pwd: 需要加密的密码 :return: 返回加密后的哈西值 ''' m = hashlib.md5(bytes( '明天更美好' ,encoding = 'utf-8' )) m.update(bytes(pwd,encoding = 'utf-8' )) return m.digest() def info_add(obj): ''' 把注册好信息写入文件 :param obj: 注册的账户对象 :return: ''' if os.path.exists(Config.ACCOUNT_INFO_PATH): with open (Config.ACCOUNT_INFO_PATH, 'rb' ) as f: li = pickle.load(f) li.append(obj) else : li = [] li.append(obj) with open (Config.ACCOUNT_INFO_PATH, 'wb' ) as f: pickle.dump(li,f) def land_usr_ver(usr): ''' 登录时验证用户名存不存在 :param usr: 需要验证用户名 :return: 存在--返回存在,不存在--返回你输入的用户名不存在 ''' if os.path.exists(Config.ACCOUNT_INFO_PATH): with open (Config.ACCOUNT_INFO_PATH, 'rb' ) as f: li = pickle.load(f) for i in li: if i.username = = usr: return '存在' return '输入的用户名不存在!请重新输入!' else : return '输入的用户名不存在!请重新输入!' def landed_ver(usr,pwd2): ''' 用于用户名和密码验证 :param usr: 验证用户名 :param pwd: 验证密码 :return: ''' pwd = encrypt(pwd2) li = pickle.load( open (Config.ACCOUNT_INFO_PATH, 'rb' )) for i in li: if i.username = = usr and i.password = = pwd: return i return '密码错误!请重新输入!' |
绝版FTP:猛戳这里
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步