zoukankan      html  css  js  c++  java
  • 〖Demo〗-- 高级FTP服务器开发

    【高级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                 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 = '
    %d%%' % (rate_num, ) #
     回到到开头
    289     sys.stdout.write(r)
    290     sys.stdout.flush()  #删除记录
    291 
    292 ftp = Ftp_client()
    293 ftp.connet('localhost', 9999)
    client
    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()
    server
  • 相关阅读:
    MPTCP iperf 发包方式
    Java 中的覆盖@Override注解 写与不写的一点点理解
    servlet 方法有哪些
    java 获取HTTP 头部信息
    七种访问方式(get post及上传文件)
    Enumeration接口的用法
    HTTP头部详解及使用Java套接字处理HTTP请求
    以debug模式启动tomcat服务器
    第一个servlet 使用out输出html文档
    基于Servlet3.0的文件上传
  • 原文地址:https://www.cnblogs.com/SHENGXIN/p/8088774.html
Copyright © 2011-2022 走看看