博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
〖Demo〗-- 高级FTP服务器开发
阅读量:5292 次
发布时间:2019-06-14

本文共 17086 字,大约阅读时间需要 56 分钟。

【高级FTP服务器开发】

要求:

1. 用户加密认证

2. 多用户同时登陆

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

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

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

6. 查看当前目录下文件

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

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

9. 支持断点续传

 

 

 

 

路径如下

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 break103 elif choose =='2':104 path = input('请输入路径,子路径用 / 分隔隔开') # 根目录不用输入105 break106 else:107 print('输入有误')108 continue109 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 False117 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)))#存在文件的size121 while True:122 choose = input('文件已存在, 1 重新下载 2 停止下载 3 新起名再下载 4 继续下载')123 if choose == '2':124 dic={}125 dic['choose'] = choose126 self.client.sendall(pickle.dumps(dic))127 return False128 elif choose == '1':129 f = open(os.path.join(A, 'db',filename),'wb')130 r_size = 0131 break132 elif choose == '3':133 name = input('请输入新文件名')134 f = open(os.path.join(A, 'db',name),'wb')135 r_size = 0136 break137 elif choose == '4':138 f = open(os.path.join(A, 'db',filename),'ab')139 break140 else:141 print('输入有误,请重新输入')142 dic={}143 dic['choose'] = choose144 dic['size'] = r_size145 self.client.sendall(pickle.dumps(dic))146 else:147 r_size = 0148 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)) #文件size172 path = input('请输入上传的路径,子路径用 / 分隔隔开, h为根目录')173 dic = {}174 dic['filename'] = filename175 dic['size'] = size176 dic['path'] = path177 self.client.sendall(pickle.dumps(dic))178 f = open(os.path.join(A, 'db', filename), 'rb')179 else:180 print ('此文件不存在')181 return False182 data = self.client.recv(1024)183 ls = pickle.loads(data) #ls[2]: ;184 if ls[-1]=='1': #ls[-1]:检查下载的路径是否存在185 print ('此路径不存在')186 return False187 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 break198 elif a == '2':199 return False200 elif a =='3':201 f_name = input('请输入新文件名')202 f_ls.append(f_name)203 break204 elif a=='4':205 l_size = ls[2] #ls[2]:已下载的文件大小206 f.seek(l_size) #把指针放到已下载的地方,继续下载207 break208 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 False224 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 False252 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 continue278 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
import socketserverimport pickleimport osimport timeA = 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',  9999server = socketserver.ThreadingTCPServer((host, port), MyTCPHandler)server.serve_forever()
server

 

转载于:https://www.cnblogs.com/SHENGXIN/p/8088774.html

你可能感兴趣的文章
用python2和python3伪装浏览器爬取网页
查看>>
MySQL开启远程连接权限
查看>>
tomcat7.0.27的bio,nio.apr高级运行模式
查看>>
SAP HANA 三大特点
查看>>
C#预处理器命令
查看>>
苹果手表:大方向和谷歌一样,硬件分道扬镳
查看>>
ccf 出现次数最多的数
查看>>
单例模式
查看>>
Competing Consumers Pattern (竞争消费者模式)
查看>>
HDUOJ ------1398
查看>>
cf--------(div1)1A. Theatre Square
查看>>
Android面试收集录15 Android Bitmap压缩策略
查看>>
Tomcat 报错的解决方法:The APR based Apache Tomcat Native library which allows optimal
查看>>
最长公共子串问题(LCS)
查看>>
TortoiseSVN is locked in another working copy
查看>>
PHP魔术方法之__call与__callStatic方法
查看>>
ubuntu 安装后的配置
查看>>
Html学习_简易个人网页制作
查看>>
angular中ng-bind指令小案例
查看>>
jqery总结
查看>>