高级FTP服务器开发
一,作业要求
高级FTP服务器开发
- 用户加密认证(完成)
- 多用户同时登陆(完成)
- 每个用户有不同家目录且只能访问自己的家目录(完成)
- 对用户进行磁盘配额,不同用户配额可不同(完成)
- 用户登录server后,可切换目录(完成)
- 查看当前目录下文件(完成)
- 上传下载文件保持文件一致性(完成)
- 传输过程中实现进度条(完成)
- 可以创建或删除目录及文件(完成)
- 支持断点续传(未做)
二,程序文件清单
- Folder目录:用户文件目录
- bin目录:程序启动文件目录
- conf目录:用户配置文件目录
- core目录:程序核心代码目录
- log目录:程序日志文件目录
三,程序流程简图
四,程序测试样图
- 创建账户
- 用户登录
- 基本操作
五,核心源码清单
- 客户端核心源码
1 #!usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # auther:Mr.chen 4 # 描述: 5 6 import socket,os 7 import time,json 8 9 10 DIR = os.path.dirname(os.path.abspath(__file__)) 11 DIR = DIR.replace('core','Folder/') 12 HOST = 'localhost' 13 PORT = 8888 14 15 16 17 18 def ls_Method(s): 19 s.send("Begin!") 20 data = '' 21 while True: 22 buffer = s.recv(1024) 23 if buffer == 'Exit!': 24 break 25 if not buffer: 26 print ("服务器传输错误!") 27 return 28 data += buffer 29 print (data) 30 31 32 def put_Method(s,action,filename): 33 if os.path.exists(DIR+filename) and os.path.isdir(DIR+filename) == False: 34 with open(DIR+filename,'r') as f: 35 data = f.read() 36 data_size = len(data) 37 s.send(str(data_size)) 38 if s.recv(1024) == 'OK!': 39 s.send(filename) 40 if s.recv(1024) == 'OK!': 41 print ("文件开始上传,请稍后...") 42 with open(DIR+filename,'r') as f: 43 Num = None 44 data = '' 45 while True: 46 buffer = f.read(1024) 47 if not buffer: 48 s.send("Exit!") 49 break 50 s.send(buffer) 51 data += buffer 52 Num = download_Progress(data_size, len(data), Num) 53 if s.recv(1024) == 'OK!': 54 print ("上传成功!磁盘配额剩余{0}M".format(s.recv(1024))) 55 else: 56 print ("文件传输有损,请重新上传!") 57 else: 58 print ("不能上传!服务器上已有重名的文件") 59 else: 60 print ("磁盘配额已满,请清理磁盘空间!") 61 else: 62 s.send("False!") 63 print ("上传失败,没有这个文件或目标是个文件夹") 64 65 66 def get_Method(s,action,filename): 67 s.send(filename) 68 print ("正在下载,请等待...") 69 data = '' 70 data_size = s.recv(1024) 71 if data_size == "Flase!": 72 print ("下载失败!服务器没有找到或目标是个文件夹") 73 return 74 data_size = int(data_size) 75 Num = None 76 while True: 77 buffer = s.recv(1024) 78 if not buffer : 79 print ("文件损坏,请重新下载!") 80 break 81 data += buffer 82 Num = download_Progress(data_size,len(data),Num) 83 if data_size == len(data): 84 with open(DIR + filename, 'w') as f: 85 f.write(data) 86 print ("下载成功!") 87 break 88 89 90 def cd_Method(s,action,filename): 91 s.send(filename) 92 re = s.recv(1024) 93 if re == 'OK!': 94 print ("命令执行成功!") 95 elif re == 'NULL!': 96 print ("已到根目录,不能继续返回!") 97 else: 98 print ("目录没有找到!") 99 100 101 def mkdir_Method(s,action,filename): 102 s.send(filename) 103 if s.recv(1024) == 'OK!': 104 print ("目录创建成功!") 105 else: 106 print ("已有同名目录或文件!") 107 108 109 def rm_Method(s,action,filename): 110 s.send(filename) 111 re = s.recv(1024) 112 if re == "OK!": 113 print ("删除成功!磁盘配额剩余{0}M".format(s.recv(1024))) 114 elif re == "DIR!": 115 while True: 116 decide = raw_input("您选择的目标是个文件夹,是否递归删除(y/n):") 117 if decide == 'y': 118 s.send("OK!") 119 re = s.recv(1024) 120 if re == "OK!": 121 print ("删除成功,磁盘配额剩余{0}M".format(s.recv(1024))) 122 break 123 else: 124 print ("删除失败,原因未知!") 125 break 126 elif decide == 'n': 127 s.send("False!") 128 break 129 else: 130 print ("您的输入有误!") 131 else: 132 print ("没有这个文件") 133 134 135 def download_Progress(size_total,size,Num): 136 num = size * 100 / size_total 137 if Num == None: 138 # print (str(num)+"%") 139 print " %d" % num, 140 time.sleep(0.01) 141 return num 142 elif num == Num: 143 return num 144 else: 145 print " %d" % num, 146 time.sleep(0.01) 147 return num 148 149 150 151 152 def MD5(password): 153 """ 154 加密函数 155 :param password: 156 :return: 157 """ 158 import hashlib 159 return hashlib.md5(password).hexdigest() 160 161 162 def File_transfer(s): 163 """ 164 用户指令函数 165 :param s: 166 :return: 167 """ 168 169 while True: 170 command = raw_input("请输入你想执行的命令>>") 171 if not command: 172 continue 173 if command.lower().strip() == 'help': 174 text = """ 175 请用'put'+'空格'+'文件名'的格式上传文件 176 请用'get'+'空格'+'文件名'的格式下载文件 177 请用'cd'+'空格'+'目录名'的格式进入家目录下的子文件夹 178 请用'cd'+'空格'+'..'的格式返回上级目录 179 请用'mkdir'+'空格'+'目录名'的格式进入家目录的文件夹 180 请用'rm'+'空格'+'文件名/目录名'的格式删除家目录下的文件 181 输入'ls'查看用户服务器家目录 182 """ 183 print (text) 184 continue 185 try: 186 action,filename = command.strip().split() 187 action = action.lower() 188 except: 189 if command.lower().strip() == 'ls': 190 s.send('ls') 191 print ("正在查询,请稍后...") 192 if s.recv(1024) == 'OK!': 193 ls_Method(s) 194 else: 195 print ("您的输入有误!输入help查看帮助文档") 196 continue 197 else: 198 s.send(action) 199 if s.recv(1024) == 'OK!': 200 eval(action+'_Method')(s,action,filename) 201 else: 202 print ("您的输入有误!输入help查看帮助文档") 203 204 205 def Login(s): 206 """ 207 用户登录 208 :param s: 209 :return: 210 """ 211 while True: 212 name = raw_input("请输入你的登陆名:").strip() 213 password = raw_input("请输入你的密码:").strip() 214 if not name or not password: 215 print ("用户名和密码不能为空!") 216 continue 217 password = MD5(password) #密码加密 218 data = [name,password] 219 s.send(json.dumps(data)) 220 if s.recv(1024) == 'OK!': 221 print ("用户登陆成功!") 222 File_transfer(s) 223 else: 224 print ("用户登陆失败!") 225 226 227 def Main(): 228 """ 229 用户登陆 230 :param s: 231 :param log: 232 :return: 233 """ 234 s = socket.socket() 235 try: 236 s.connect((HOST, PORT)) 237 s.send("Ready!") 238 239 data = s.recv(1024) #接收服务器欢迎信息 240 if not data: 241 print ("服务器异常!") 242 else: 243 print (data) 244 Login(s) 245 except Exception,e: 246 print "服务器连接不上....", e 247 finally: 248 s.close() 249 250 251 if __name__ == "__main__": 252 Main()
- 服务器端核心源码
1 #!usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # auther:Mr.chen 4 # 描述: 5 6 import SocketServer 7 import os,time,sys,json 8 import admin_configure 9 DIR = os.path.dirname(os.path.abspath(__file__)) 10 DIR = DIR.replace('core','Folder/') 11 12 13 14 class Myserver(SocketServer.BaseRequestHandler): 15 16 def __init__(self,request,client_address,server): 17 SocketServer.BaseRequestHandler.__init__(self,request,client_address,server) 18 self.Name = '' #用户名 19 self.Password = '' #用户密码 20 self.Quota = '' #用户磁盘配额 21 self.Home_path = '' #用户家目录路径 22 self.Current_path = '' #用户当前路径 23 self.DIR = [] #用户进入过的子目录列表 24 25 26 27 def ls_Method(self): 28 data = self.request.recv(1024) 29 if data == 'Begin!': 30 data = os.popen('ls'+' '+self.Current_path).read() 31 self.request.sendall(data) 32 time.sleep(0.5) 33 self.request.send("Exit!") 34 35 36 def put_Method(self): 37 data_size = self.request.recv(1024) 38 if data_size == 'False!': 39 return 40 if int(self.Quota) >= int(data_size): 41 self.request.send("OK!") 42 filename = self.request.recv(1024) 43 if os.path.exists(self.Current_path+filename) == False: 44 self.request.send("OK!") 45 data = '' 46 while True: 47 buffer = self.request.recv(1024) 48 if buffer == 'Exit!': 49 break 50 if not buffer: 51 break 52 data += buffer 53 self.Quota = str(int(self.Quota) - len(data)) 54 dict = admin_configure.config_read(self.Name) 55 dict['Quota'] = self.Quota 56 admin_configure.config_write(dict) 57 with open(self.Current_path+filename,'w') as f: 58 f.write(data) 59 if len(data) == int(data_size): 60 self.request.send("OK!") 61 time.sleep(0.25) 62 Quota = str(float(self.Quota)/1000000) 63 self.request.send(Quota) 64 else: 65 self.request.send("Flase!") 66 else: 67 self.request.send("False!") 68 else: 69 self.request.send("Flase!") 70 71 72 73 def get_Method(self): 74 filename = self.request.recv(1024) 75 if os.path.exists(self.Current_path+filename) and os.path.isdir(self.Current_path+filename) == False: 76 with open(self.Current_path+filename,'r') as f: 77 data = f.read() 78 self.request.send(str(len(data))) 79 time.sleep(0.5) 80 self.request.sendall(data) 81 else: 82 self.request.send("Flase!") 83 84 85 86 87 88 def cd_Method(self): 89 filename = self.request.recv(1024) 90 if filename == '..': 91 if len(self.DIR) == 0: 92 self.request.send("NULL!") 93 return 94 else: 95 # self.Current_path = self.Current_path.replace('/'+self.DIR[0]+'/','/') 96 list = self.Current_path.split('/') 97 del list[0] 98 del list[len(list) - 1] 99 del list[len(list) - 1] 100 str = '/' 101 for i in range(len(list)): 102 str = str + list[i] + '/' 103 self.Current_path = str 104 del self.DIR[0] 105 self.request.send("OK!") 106 elif os.path.isdir(self.Current_path+filename): 107 self.Current_path = self.Current_path + filename + '/' 108 self.DIR.insert(0,filename) 109 self.request.send("OK!") 110 else: 111 self.request.send("False!") 112 113 114 def mkdir_Method(self): 115 filename = self.request.recv(1024) 116 if os.path.exists(self.Current_path+filename): 117 self.request.send("False!") 118 else: 119 os.system("mkdir -p " + self.Current_path + filename) 120 if os.path.exists(self.Current_path + filename): 121 self.request.send("OK!") 122 else: 123 self.request.send("False!") 124 125 def rm_Method(self): 126 filename = self.request.recv(1024) 127 if os.path.exists(self.Current_path+filename): 128 if os.path.isdir(self.Current_path+filename): 129 self.request.send("DIR!") 130 if self.request.recv(1024) == "OK!": 131 data = os.popen('du'+' '+ '-sk' + ' ' + self.Current_path+filename).read() 132 data_size,file = data.strip().split() 133 os.system("rm -rf " + self.Current_path + filename) 134 self.Quota = str(int(self.Quota) + int(data_size)) 135 dict = admin_configure.config_read(self.Name) 136 dict['Quota'] = self.Quota 137 admin_configure.config_write(dict) 138 self.request.send("OK!") 139 time.sleep(0.25) 140 Quota = str(float(self.Quota) / 1000000) 141 self.request.send(Quota) 142 143 else: 144 return 145 else: 146 with open(self.Current_path+filename,'r') as f: 147 data = f.read() 148 os.system("rm -f " + self.Current_path + filename) 149 self.Quota = str(int(self.Quota) + len(data)) 150 dict = admin_configure.config_read(self.Name) 151 dict['Quota'] = self.Quota 152 admin_configure.config_write(dict) 153 self.request.send("OK!") 154 time.sleep(0.25) 155 Quota = str(float(self.Quota) / 1000000) 156 self.request.send(Quota) 157 else: 158 self.request.send("False!") 159 160 def Login_Method(self,data): 161 re = admin_configure.config_read(data[0]) 162 if re == None: 163 return False 164 else: 165 if re['Password'] == data[1]: 166 self.Name = re['Name'] 167 self.Password = re['Password'] 168 self.Quota = re['Quota'] 169 self.Home_path = re['Home_path'] 170 self.Current_path = re['Current_path'] 171 self.DIR = [] 172 return True 173 else: 174 return False 175 176 177 178 179 180 181 182 def handle(self): 183 conn = self.request 184 conn.recv(1024) 185 print ("收到来自{0}的客户端连接...".format(self.client_address[0])) 186 conn.send("欢迎你!") 187 try: 188 while True: 189 print ("正在等待客户端发送验证信息!") 190 self.data = json.loads(conn.recv(1024)) 191 # if not self.data: 192 # break 193 if not self.data or type(self.data) != list: 194 conn.send("false!") 195 else: 196 re = self.Login_Method(self.data) 197 if re == True: 198 print ("客户端认证成功!") 199 conn.send("OK!") 200 while True: 201 print ("正在等待客户端响应...") 202 data = conn.recv(1024) 203 # if not data: 204 # break 205 if hasattr(self,data +'_Method'): 206 conn.send("OK!") 207 getattr(self,data +'_Method')() 208 else: 209 conn.send("flase") 210 211 else: 212 conn.send("flase!") 213 except Exception,e: 214 print "客户端失去连接!",e 215 216 def Main(): 217 HOST = 'localhost' 218 PORT = 8888 219 s = SocketServer.ThreadingTCPServer((HOST, PORT), Myserver) 220 print ("正在等待客户端连接...") 221 s.serve_forever() 222 223 224 225 if __name__ == "__main__": 226 Main()