要求:服務器
1. 用戶加密認證app
2. 多用戶同時登錄socket
3. 每一個用戶有本身的家目錄且只能訪問本身的家目錄ide
4. 對用戶進行磁盤配額、不一樣用戶配額可不一樣加密
5. 用戶能夠登錄server後,可切換目錄spa
6. 查看當前目錄下文件指針
7. 上傳下載文件,保證文件一致性code
8. 傳輸過程當中現實進度條server
9. 支持斷點續傳blog
路徑以下
1 import socket 2 import pickle 3 import hashlib 4 import sys 5 import time 6 import os 7 A = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 8 class Ftp_client(object): 9 def __init__(self): 10 self.client = socket.socket() 11 def help(self): 12 ''' 13 幫助說明 14 :return: 15 ''' 16 print('''請輸入正確的指令: 17 ls: 查看根目錄下文件 18 cd: 切換目錄 19 download: 下載文件 20 upload:上文件 21 mkdir:新創建文件夾 22 ''') 23 def connet(self, ip, port): 24 ''' 25 連接服務器 26 :param ip: 27 :param port: 28 :return: 29 ''' 30 self.client.connect((ip, port)) 31 data = self.client.recv(1024) 32 print(data.decode()) 33 self.main() 34 self.ftp_main() 35 def login(self): 36 ''' 37 登陸 38 :return: 39 ''' 40 name = input('請輸入姓名').lower() 41 password = input('請輸入密碼') 42 dict = {'name': name, 'password': password} 43 self.client.sendall(pickle.dumps(dict)) 44 data = self.client.recv(1024) 45 print(data.decode()) 46 if data.decode()=='輸入有誤': 47 return False 48 def register(self): 49 ''' 50 註冊 51 :return: 52 ''' 53 while True: 54 a = input('請輸入註冊哪一種用戶: 1: 普通用戶(可用空間10M), 2: VIP用戶(可用30M)') 55 if a =='1': 56 space = 10485760 57 break 58 elif a== '2': 59 space = 31457280 60 break 61 else: 62 print('輸入有誤') 63 continue 64 name = input('請輸入姓名').lower() 65 pd = input('請輸入密碼') 66 dict = {'name': name, 'password': pd, 'space': space} 67 self.client.sendall(pickle.dumps(dict)) 68 data = self.client.recv(1024) 69 print(data.decode()) 70 if data.decode()== '用戶名已存在,請從新輸入': 71 return False 72 73 def main(self): 74 while True: 75 a = input('請輸入 1. 用戶登陸 2. 用戶註冊 3.退出') 76 if a == '1': 77 self.client.sendall('login'.encode()) 78 res = self.login() 79 elif a == '2': 80 self.client.sendall('register'.encode()) 81 res = self.register() 82 elif a == '3': 83 exit() 84 else: 85 print('輸入有誤') 86 continue 87 if res is False: 88 continue 89 else: 90 break 91 92 def download(self): 93 ''' 94 下載 95 :return: 96 ''' 97 while True: 98 data = self.client.recv(1024) 99 choose = input('文件所在路徑 1 根目錄 2 子目錄') 100 if choose == '1': 101 path = '1' 102 break 103 elif choose =='2': 104 path = input('請輸入路徑,子路徑用 / 分隔隔開') # 根目錄不用輸入 105 break 106 else: 107 print('輸入有誤') 108 continue 109 self.client.sendall(path.encode()) 110 data = self.client.recv(1024) 111 filename = input('請輸入下載文件名') 112 self.client.sendall(filename.encode()) 113 size = self.client.recv(1024).decode() 114 if size == '該文件不存在': 115 print ('該文件不存在') 116 return False 117 else: 118 size = int(size) 119 if os.path.exists(os.path.join(A, 'db', filename)): 120 r_size = int(os.path.getsize(os.path.join(A, 'db', filename)))#存在文件的size 121 while True: 122 choose = input('文件已存在, 1 從新下載 2 中止下載 3 新起名再下載 4 繼續下載') 123 if choose == '2': 124 dic={} 125 dic['choose'] = choose 126 self.client.sendall(pickle.dumps(dic)) 127 return False 128 elif choose == '1': 129 f = open(os.path.join(A, 'db',filename),'wb') 130 r_size = 0 131 break 132 elif choose == '3': 133 name = input('請輸入新文件名') 134 f = open(os.path.join(A, 'db',name),'wb') 135 r_size = 0 136 break 137 elif choose == '4': 138 f = open(os.path.join(A, 'db',filename),'ab') 139 break 140 else: 141 print('輸入有誤,請從新輸入') 142 dic={} 143 dic['choose'] = choose 144 dic['size'] = r_size 145 self.client.sendall(pickle.dumps(dic)) 146 else: 147 r_size = 0 148 f = open(os.path.join(A, 'db', filename),'xb') 149 150 151 if size == 0: 152 f.close() 153 print('接收完成') 154 else: 155 while r_size < size: 156 file = self.client.recv(1024) 157 f.write(file) 158 f.flush() #文件強行寫入file,預防中途中斷 159 r_size += len(file) 160 view_bar(r_size, size) 161 time.sleep(0.1) 162 else: 163 print('接收完成') 164 f.close() 165 166 167 168 def upload(self): 169 filename = input('請輸入上傳的文件名') 170 if os.path.exists(os.path.join(A, 'db', filename)): 171 size = os.path.getsize(os.path.join(A, 'db', filename)) #文件size 172 path = input('請輸入上傳的路徑,子路徑用 / 分隔隔開, h爲根目錄') 173 dic = {} 174 dic['filename'] = filename 175 dic['size'] = size 176 dic['path'] = path 177 self.client.sendall(pickle.dumps(dic)) 178 f = open(os.path.join(A, 'db', filename), 'rb') 179 else: 180 print ('此文件不存在') 181 return False 182 data = self.client.recv(1024) 183 ls = pickle.loads(data) #ls[2]: ; 184 if ls[-1]=='1': #ls[-1]:檢查下載的路徑是否存在 185 print ('此路徑不存在') 186 return False 187 if ls[0] == '0':#ls[0]:檢查空間夠不夠; 188 print ('空間不足,不能上傳') 189 190 else: 191 if ls[1] == '0': #ls[1]:檢查下載是否存在 192 while True: 193 a = input('文件已存在, 1 從新下載 2 中止下載 3 新起名再下載 4 繼續下載') 194 f_ls = [] 195 f_ls.append(a) 196 if a == '1': 197 break 198 elif a == '2': 199 return False 200 elif a =='3': 201 f_name = input('請輸入新文件名') 202 f_ls.append(f_name) 203 break 204 elif a=='4': 205 l_size = ls[2] #ls[2]:已下載的文件大小 206 f.seek(l_size) #把指針放到已下載的地方,繼續下載 207 break 208 else: 209 print ('輸入有誤') 210 else: 211 f_ls = [] 212 f_ls.append('5') # 5:下載文件不存在 213 self.client.sendall(pickle.dumps(f_ls)) 214 data = self.client.recv(1024).decode() 215 print (data) 216 for line in f: 217 self.client.sendall(line) 218 num = f.tell() #查看文件上傳位置 219 view_bar(num, size) 220 time.sleep(0.1) 221 f.close() 222 print ('接收完成') 223 return False 224 225 226 def ls(self): 227 data = self.client.recv(1024) 228 if data =='0'.encode(): 229 print('此目錄爲空') 230 elif data =='1'.encode(): 231 print('此文件不存在') 232 else: 233 ls = pickle.loads(data) 234 print('此文件裏有:') 235 for i in ls: 236 print(i) 237 238 def mkdir(self): 239 name = input('請輸入文件夾名') 240 self.client.sendall(name.encode()) 241 data = self.client.recv(1024).decode() 242 print(data) 243 244 def cd(self): 245 name = input('請輸入路徑,子路徑用 / 分隔隔開') # 根目錄不用輸入 246 self.client.sendall(name.encode()) 247 path = self.client.recv(1024).decode() 248 249 if path == '0': 250 print ('此目錄不存在') 251 return False 252 else: 253 print ('所在文件夾路徑爲 %s' % path) 254 self.client.sendall('ok'.encode()) 255 data = self.client.recv(1024) 256 if data =='0'.encode(): 257 print('此目錄爲空') 258 else: 259 ls = pickle.loads(data) 260 print('此文件裏有:') 261 for i in ls: 262 print(i) 263 264 265 266 def ftp_main(self): 267 while True: 268 a = input('請輸入相應的指令, help:查詢, exit:退出') 269 if hasattr(self, a): 270 self.client.sendall(a.encode()) 271 func = getattr(self, a) 272 func() 273 elif a == 'exit': 274 exit() 275 else: 276 self.help() 277 continue 278 279 280 281 282 283 284 def view_bar(num, total): 285 '''進度條''' 286 rate = float(num) / float(total) 287 rate_num = int(rate * 100) 288 r = '\r%d%%' % (rate_num, ) #\r 回到到開頭 289 sys.stdout.write(r) 290 sys.stdout.flush() #刪除記錄 291 292 ftp = Ftp_client() 293 ftp.connet('localhost', 9999)
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 = '0' #空間不足 s_ls.append(a) else: a = '1' 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 = '0' #文件已存在 file_size = os.path.getsize(l_path) s_ls.append(b) s_ls.append(file_size) else: b = '1' s_ls.append(b) if os.path.exists(b_path): c = '0' else: c='1'#文件夾不存在,能夠結束 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] =='1': f = open(l_path,'wb') file_size = 0 elif f_ls[0]=='2': return False elif f_ls[0]=='3':#文件名另起 filename = f_ls[1] l_path = os.path.join(b_path,filename) f = open(l_path,'wb') file_size = 0 elif f_ls[0]=='4': 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 == '1': 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']=='2': return False elif dic['choose']=='4': 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('0'.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 = '0' 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('0'.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()