【高级FTP服务器开发】

要求:

1. 用户加密认证

2. 多用户同时登陆

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

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

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

6. 查看当前目录下文件

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

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

9. 支持断点续传

 

 

 

〖Demo〗-- 高级FTP服务器开发

 

路径如下

〖Demo〗-- 高级FTP服务器开发

  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)
client

相关文章:

  • 2021-06-17
  • 2021-11-09
  • 2021-05-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-09-11
  • 2021-07-31
  • 2021-11-18
  • 2021-12-27
  • 2022-12-23
  • 2021-11-17
  • 2021-11-18
相关资源
相似解决方案