zoukankan      html  css  js  c++  java
  • socketserver实现FTP


    功能:
    1、用户加密认证
    2、允许同时多用户登录
    3、每个用户有自己的家目录 ,且只能访问自己的家目录
    4、对用户进行磁盘配额,每个用户的可用空间不同
    5、允许用户在ftp server上随意切换目录
    6、允许用户查看当前目录下文件
    7、允许上传和下载文件,保证文件一致性
    8、文件传输过程中显示进度条
    附加功能:支持文件的断点续传

    环境
      
    python 3.5

    特性:
      用socketserver实现FTP

    主要功能实现:
      1、用户加密认证
        ConfigParser 是Python自带的模块, 用来读写配置文件,将用户信息以下边的格式存入account.py文件,读出后进行判断
    [DEFAULT]
    
    [alex]
    Password = 123456
    Quotation = 100
    
    [jack]
    Password = 123456
    Quotation = 100

        2、允许同时多用户登录
          从scokerserver 继承 socketserver.ThreadingTCPServer即可实现
        3、每个用户有自己的家目录 ,且只能访问自己的家目录
          将所有路径封装在home目录下
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    USER_HOME = '%shome' % BASE_DIR
    LOG_DIR = '%slog' % BASE_DIR
    LOG_LEVEL = 'DEBUG'
        4、允许用户在ftp server上随意切换目录
          用os模块改变工作目录
    os.chdir(func_val)
        5、允许用户查看当前目录下文件
          用os模块的os.listdir,下为server端代码
        def _ls(self,*args,**kwargs):
            '''显示当前目录下的所有文件'''
            if os.getcwd() == '%s\bin'% settings.BASE_DIR:
                user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])
                self.request.send(json.dumps(os.listdir(user_home_dir)).encode())
            else:self.request.send(json.dumps(os.listdir()).encode())
        6、允许上传和下载文件,保证文件一致性
          判断上传和下载的文件在传输前后的大小,用以判断文件是否保持一致
      1 #server端
      2 #
      3     def _put(self,*args,**kwargs):
      4         '''上传文件命令'''
      5         data = args[0]
      6 
      7         response = self.get_response()
      8         if response["status_code"] == 257:  # ready to receive
      9             self.request.send(b'1')  # send confirmation to server
     10             user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])
     11             base_filename = "%s\%s" % (user_home_dir, data.get('filename'))
     12             received_size = 0
     13             file_obj = open(base_filename, 'wb')
     14             if data.get('md5'):
     15                 md5_obj = hashlib.md5()
     16                 while received_size < response['file_size']:
     17                     line = self.request.recv(4096)
     18                     received_size += len(line)
     19                     file_obj.write(line)
     20                     md5_obj.update(line)
     21                 else:
     22                     file_obj.close()
     23                     md5_val = md5_obj.hexdigest()
     24                     self.send_response(258, {'md5': md5_val})
     25                     print("-----file rece done-----")
     26 
     27             else:
     28                 while received_size < response['file_size']:
     29                     data = self.request.recv(4096)
     30                     received_size += len(data)
     31                     file_obj.write(data)
     32                 else:
     33                     print("-----file rece done-----")
     34                     file_obj.close()
     35         else:
     36             print(STATUS_CODE[response["status_code"]])
     37 
     38 
     39     def _get(self,*args,**kwargs):
     40         '''下载文件命令'''
     41         data = args[0]
     42         if data.get('filename') is None:
     43             self.send_response(255)
     44         user_home_dir = "%s\%s" %(settings.USER_HOME,self.user["Username"])
     45         file_abs_path = "%s\%s" %(user_home_dir,data.get('filename'))
     46         print("file abs path",file_abs_path)
     47 
     48         if os.path.isfile(file_abs_path):
     49             file_obj = open(file_abs_path,'rb')
     50             file_size = os.path.getsize(file_abs_path)
     51             self.send_response(257,data = {'file_size':file_size})
     52             self.request.recv(1)    #等待客户端确认,防粘包
     53 
     54             if data.get('md5'):
     55                 md5_obj = hashlib.md5()
     56                 for line in file_obj:
     57                     self.request.send(line)
     58                     md5_obj.update(line)
     59                 else:
     60                     file_obj.close()
     61                     md5_val = md5_obj.hexdigest()
     62                     self.send_response(258,{'md5':md5_val})
     63                     print("send file done...")
     64             else:
     65                 for line in file_obj:
     66                     self.request.send(line)
     67                 else:
     68                     file_obj.close()
     69                     print("send file done...")
     70         else:
     71             self.send_response(256)
     72 
     73 
     74 
     75 
     76 # client端
     77 #
     78     def _get(self,cmd_list):
     79         '''下载文件'''
     80         print("get--",cmd_list)
     81         if len(cmd_list) == 1:
     82             print("no filename follows...")
     83             return
     84         data_header = {
     85             'action':'get',
     86             'filename':cmd_list[1]
     87         }
     88         if self.__md5_required(cmd_list):
     89             data_header['md5'] = True
     90 
     91         self.sock.send(json.dumps(data_header).encode())
     92         response = self.get_response()
     93         print(response)
     94         try:
     95             if response["status_code"] == 257:#ready to receive
     96                 self.sock.send(b'1') #send confirmation to server
     97                 base_filename = cmd_list[1].split('/')[-1]
     98                 received_size = 0
     99                 file_obj = open(base_filename,'wb')
    100                 if self.__md5_required(cmd_list):
    101                     md5_obj = hashlib.md5()
    102                     progress = self.show_progress(response['file_size']) #generator
    103                     progress.__next__()
    104                     while received_size < response['file_size']:
    105                         data = self.sock.recv(4096)
    106                         received_size += len(data)
    107                         try:
    108                             progress.send(len(data))
    109                         except StopIteration as e:
    110                             print("100%")
    111                         file_obj.write(data)
    112                         md5_obj.update(data)
    113                     else:
    114                         print("-----file rece done-----")
    115                         file_obj.close()
    116                         md5_val = md5_obj.hexdigest()
    117                         md5_from_server = self.get_response()
    118                         if md5_from_server['status_code'] == 258:
    119                             if md5_from_server['md5'] == md5_val:
    120                                 print("%s 文件一致性校验成功!"% base_filename)
    121                         print(md5_val,md5_from_server)
    122 
    123                 else:
    124                     progress = self.show_progress(response['file_size'])  # generator
    125                     progress.__next__()
    126                     while received_size < response['file_size']:
    127                         data = self.sock.recv(4096)
    128                         received_size += len(data)
    129                         file_obj.write(data)
    130                         try:
    131                             progress.send(len(data))
    132                         except StopIteration as e:
    133                             print("100%")
    134                     else:
    135                         print("-----file rece done-----")
    136                         file_obj.close()
    137             else:
    138                 print(STATUS_CODE[response["status_code"]])
    139         except Exception as e:
    140             base_file_size = os.path.getsize(base_filename)
    141             with open('data\breakpoint', 'wb') as br_po:
    142                 data_header['action'] = 'breakpoint'
    143                 data_header['breakpoint'] = base_file_size
    144                 br_po.write(json.dumps(data_header).encode())
    145 
    146 
    147     def _put(self,cmd_list):
    148         '''上传文件'''
    149         print("put--", cmd_list)
    150         if len(cmd_list) == 1:
    151             print("no filename follows...")
    152             return
    153         data_header = {
    154             'action': 'put',
    155             'filename': cmd_list[1]
    156         }
    157         if self.__md5_required(cmd_list):
    158             data_header['md5'] = True
    159 
    160         self.sock.send(json.dumps(data_header).encode())
    161         if os.path.isfile(cmd_list[1]):
    162             file_obj = open(cmd_list[1], 'rb')
    163             file_size = os.path.getsize(cmd_list[1])
    164             self.send_response(257, data={'file_size': file_size})
    165             self.sock.recv(1)  # 等待服务器端确认
    166             if self.__md5_required(cmd_list):
    167                 md5_obj = hashlib.md5()
    168                 progress = self.show_progress(file_size)  # generator
    169                 progress.__next__()
    170                 for line in file_obj:
    171                     self.sock.send(line)
    172                     try:
    173                         progress.send(len(line))
    174                     except StopIteration as e:
    175                         print("100%")
    176                     md5_obj.update(line)
    177                 else:
    178                     file_obj.close()
    179                     md5_val = md5_obj.hexdigest()
    180                     md5_from_server = self.get_response()
    181                     if md5_from_server['md5'] == md5_val:
    182                             print("%s 文件一致性校验成功!"% cmd_list[1])
    183                     self.send_response(258, {'md5': md5_val})
    184                     print("send file done...")
    185             else:
    186                 progress = self.show_progress(file_size)  # generator
    187                 progress.__next__()
    188                 for line in file_obj:
    189                     self.sock.send(line)
    190                     try:
    191                         progress.send(len(line))
    192                     except StopIteration as e:
    193                         print("100%")
    194                 else:
    195                     file_obj.close()
    196                     print("send file done...")
    197         else:
    198             print(256)
    get and put
        7、文件传输过程中显示进度条
          根据已传文件大小和总文件大小比对判断,输出符号
     1     def show_progress(self,total):
     2         '''显示进度条
     3            total: 文件大小'''
     4         received_size = 0
     5         current_percent = 0
     6         while received_size < total:
     7             if int((received_size / total) * 100) > current_percent:
     8                 print(">",end='',flush=True)
     9                 current_percent = int((received_size / total) * 100)
    10             new_size = yield
    11             received_size += new_size
    进度条
        附加功能:支持文件的断点续传
          将上次断点信息记录下来,也就是记录已传文件大小,再次启用时,将目标文件光标移到上次断点处,然后进行续传
     1     def _breakpoint(self,*args,**kwargs):
     2         '''断点续传'''
     3         data = args[0]
     4         if data.get('filename') is None:
     5             self.send_response(255)
     6         user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])
     7         file_abs_path = "%s\%s" % (user_home_dir, data.get('filename'))
     8         print("file abs path", file_abs_path)
     9         print(data.get('breakpoint'))
    10 
    11         if os.path.isfile(file_abs_path):
    12             file_obj = open(file_abs_path, 'rb')
    13             file_obj.seek(data.get('breakpoint'))
    14             file_size = os.path.getsize(file_abs_path)
    15             self.send_response(257, data={'file_size': file_size})
    16             self.request.recv(1)  # 等待客户端确认
    17 
    18             if data.get('md5'):
    19                 md5_obj = hashlib.md5()
    20                 for line in file_obj:
    21                     self.request.send(line)
    22                     md5_obj.update(line)
    23                 else:
    24                     file_obj.close()
    25                     md5_val = md5_obj.hexdigest()
    26                     self.send_response(258, {'md5': md5_val})
    27                     print("send file done...")
    28             else:
    29                 for line in file_obj:
    30                     self.request.send(line)
    31                 else:
    32                     file_obj.close()
    33                     print("send file done...")
    34         else:
    35             self.send_response(256)
    36         pass
    breakpoint

       主要知识点:

        类的继承
    os模块的应用
    json模块的应用
    类方法的运用
    md5加密方法
    scoket链接
    scoketserver链接
    反射
    异常处理


    小结:
    这个程序主要用socketserver实现了一台服务器链接多个客户端,并且进行信息交互,并且实现了几个简单的功能,如:get 文件下载、put 上传文件、cd 切换目录、ls 查看文件、breakpoint断点续传。

    主要代码:
      1 #server端
      2 #
      3 
      4 
      5 import os,sys
      6 import hashlib
      7 import socket
      8 import socketserver
      9 import json
     10 import configparser
     11 from conf import settings
     12 
     13 
     14 STATUS_CODE = {
     15     250 : "Invalid cmd format,e.g:{'action':'get','filename':'test.py','size':344",
     16     251 : "Invalid cmd",
     17     252 : "Invalid auth data",
     18     253 : "Wrong username or password..",
     19     254 : "Passed authentication",
     20     255 : "Filename doesn't provided",
     21     256 : "File doesn't exist on server",
     22     257 : "ready to send file",
     23     258 : "md5 verification",
     24     259 : "Directory has been switched"
     25 }
     26 
     27 
     28 
     29 
     30 
     31 class FTPHandler(socketserver.BaseRequestHandler):
     32     '''定义request handler类,从BaseRequestHandler类继承'''
     33     def handle(self):
     34         '''
     35         获取服务器端的信息
     36         如果传来cd命令,改变工作目录
     37         '''
     38 
     39         while True:
     40             self.data = self.request.recv(1024).strip()
     41             if not self.data:
     42                 print('Client closed..')
     43                 break
     44             data = json.loads(self.data.decode())
     45             if data.get('action') is not None:
     46                 if hasattr(self,'_%s'%data.get('action')):
     47                     func =getattr(self,'_%s'%data.get('action'))
     48                     func_val = func(data)
     49                     if data.get('action') == 'cd':     #cd 命令,改变工作目录
     50                         os.chdir(func_val)
     51                     else:pass
     52                 else:
     53                     print('Invalid cmd')
     54                     self.send_response(251)
     55             else:
     56                 print('Invalid cmd format')
     57                 self.send_response(250)
     58 
     59 
     60     def send_response(self,status_code,data=None):
     61         '''向客户端返回数据'''
     62         response = {'status_code': status_code, 'status_msg':STATUS_CODE[status_code]}
     63         if data:
     64             response.update(data)
     65         self.request.send(json.dumps(response).encode())
     66 
     67 
     68     def _auth(self,*args,**kwargs):
     69         '''判断用户是否输入完整的用户名和密码
     70            验证用户名和密码是否合法'''
     71         data = args[0]
     72         if data.get('username') is None or data.get('password') is None:
     73             self.send_response(252)
     74 
     75         user = self.authenticate(data.get('username'),data.get('password'))
     76         if user is None:
     77             self.send_response(253)
     78         else:
     79             print('passed authentication',user)
     80             self.user = user
     81             self.send_response(254)
     82 
     83 
     84     def authenticate(self,username,password):       #
     85         '''验证用户合法性,合法返回用户数据'''
     86         config = configparser.ConfigParser()
     87         config.read(settings.ACCOUNT_FILE)
     88         if username in config.sections():
     89             _password = config[username]['Password']
     90             if _password == password:
     91                 print('pass auth..',username)
     92                 config[username]["Username"] = username
     93                 return config[username]
     94 
     95 
     96     def get_response(self):
     97         '''接收客户端回复结果'''
     98         data = self.request.recv(1024)
     99         data = json.loads(data.decode())
    100         return data
    101 
    102 
    103     def show_progress(self,total):
    104         '''显示进度条
    105            total: 文件大小'''
    106         received_size = 0
    107         current_percent = 0
    108         while received_size < total:
    109             if int((received_size / total) * 100) > current_percent:
    110                 print(">",end='',flush=True)
    111                 current_percent = int((received_size / total) * 100)
    112             new_size = yield
    113             received_size += new_size
    114 
    115 
    116     def _put(self,*args,**kwargs):
    117         '''上传文件命令'''
    118         data = args[0]
    119 
    120         response = self.get_response()
    121         if response["status_code"] == 257:  # ready to receive
    122             self.request.send(b'1')  # send confirmation to server
    123             user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])
    124             base_filename = "%s\%s" % (user_home_dir, data.get('filename'))
    125             received_size = 0
    126             file_obj = open(base_filename, 'wb')
    127             if data.get('md5'):
    128                 md5_obj = hashlib.md5()
    129                 while received_size < response['file_size']:
    130                     line = self.request.recv(4096)
    131                     received_size += len(line)
    132                     file_obj.write(line)
    133                     md5_obj.update(line)
    134                 else:
    135                     file_obj.close()
    136                     md5_val = md5_obj.hexdigest()
    137                     self.send_response(258, {'md5': md5_val})
    138                     print("-----file rece done-----")
    139 
    140             else:
    141                 while received_size < response['file_size']:
    142                     data = self.request.recv(4096)
    143                     received_size += len(data)
    144                     file_obj.write(data)
    145                 else:
    146                     print("-----file rece done-----")
    147                     file_obj.close()
    148         else:
    149             print(STATUS_CODE[response["status_code"]])
    150 
    151 
    152     def _get(self,*args,**kwargs):
    153         '''下载文件命令'''
    154         data = args[0]
    155         if data.get('filename') is None:
    156             self.send_response(255)
    157         user_home_dir = "%s\%s" %(settings.USER_HOME,self.user["Username"])
    158         file_abs_path = "%s\%s" %(user_home_dir,data.get('filename'))
    159         print("file abs path",file_abs_path)
    160 
    161         if os.path.isfile(file_abs_path):
    162             file_obj = open(file_abs_path,'rb')
    163             file_size = os.path.getsize(file_abs_path)
    164             self.send_response(257,data = {'file_size':file_size})
    165             self.request.recv(1)    #等待客户端确认,防粘包
    166 
    167             if data.get('md5'):
    168                 md5_obj = hashlib.md5()
    169                 for line in file_obj:
    170                     self.request.send(line)
    171                     md5_obj.update(line)
    172                 else:
    173                     file_obj.close()
    174                     md5_val = md5_obj.hexdigest()
    175                     self.send_response(258,{'md5':md5_val})
    176                     print("send file done...")
    177             else:
    178                 for line in file_obj:
    179                     self.request.send(line)
    180                 else:
    181                     file_obj.close()
    182                     print("send file done...")
    183         else:
    184             self.send_response(256)
    185 
    186 
    187 
    188     def _ls(self,*args,**kwargs):
    189         '''显示当前目录下的所有文件'''
    190         if os.getcwd() == '%s\bin'% settings.BASE_DIR:
    191             user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])
    192             self.request.send(json.dumps(os.listdir(user_home_dir)).encode())
    193         else:self.request.send(json.dumps(os.listdir()).encode())
    194 
    195 
    196 
    197     def _cd(self,*args,**kwargs):
    198         '''改变工作目录'''
    199         data = args[0]
    200         user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])
    201         file_abs_path = "%s\%s" %(user_home_dir,data.get('path'))
    202         try:
    203             os.listdir(file_abs_path)
    204         except FileNotFoundError as e:
    205             self.request.send(json.dumps(e).encode())
    206             return
    207         self.request.send(json.dumps(259).encode())
    208         os.chdir(file_abs_path)
    209         return file_abs_path
    210 
    211 
    212     def _breakpoint(self,*args,**kwargs):
    213         '''断点续传'''
    214         data = args[0]
    215         if data.get('filename') is None:
    216             self.send_response(255)
    217         user_home_dir = "%s\%s" % (settings.USER_HOME, self.user["Username"])
    218         file_abs_path = "%s\%s" % (user_home_dir, data.get('filename'))
    219         print("file abs path", file_abs_path)
    220         print(data.get('breakpoint'))
    221 
    222         if os.path.isfile(file_abs_path):
    223             file_obj = open(file_abs_path, 'rb')
    224             file_obj.seek(data.get('breakpoint'))
    225             file_size = os.path.getsize(file_abs_path)
    226             self.send_response(257, data={'file_size': file_size})
    227             self.request.recv(1)  # 等待客户端确认
    228 
    229             if data.get('md5'):
    230                 md5_obj = hashlib.md5()
    231                 for line in file_obj:
    232                     self.request.send(line)
    233                     md5_obj.update(line)
    234                 else:
    235                     file_obj.close()
    236                     md5_val = md5_obj.hexdigest()
    237                     self.send_response(258, {'md5': md5_val})
    238                     print("send file done...")
    239             else:
    240                 for line in file_obj:
    241                     self.request.send(line)
    242                 else:
    243                     file_obj.close()
    244                     print("send file done...")
    245         else:
    246             self.send_response(256)
    247         pass
    server端
      1 #client端
      2 #
      3 
      4 import socket
      5 import hashlib
      6 import os,json
      7 import optparse
      8 import socketserver
      9 
     10 
     11 STATUS_CODE = {
     12     250 : "Invalid cmd format,e.g:{'action':'get','filename':'test.py','size':344",
     13     251 : "Invalid cmd",
     14     252 : "Invalid auth data",
     15     253 : "Wrong username or password..",
     16     254 : "Passed authentication",
     17     255 : "Filename doesn't provided",
     18     256 : "File doesn't exist on server",
     19     257 : "ready to send file",
     20     258 : "md5 verification",
     21     259 : "Directory has been switched"
     22 }
     23 
     24 
     25 
     26 
     27 class FTPClient(object):
     28     '''客户端'''
     29     def __init__(self):
     30         '''用户信息输入格式化
     31             变量定义'''
     32         parser = optparse.OptionParser()
     33         parser.add_option('-s', '--server', dest='server', help ='ftp server ip_addr')
     34         parser.add_option('-p','--port', type='int', dest='port', help='ftp server port')
     35         parser.add_option('-U', '--username', dest='username', help='username')
     36         parser.add_option('-P', '--Password', dest='password', help='password')
     37         self.options, self.args = parser.parse_args()
     38         self.verify_args(self.options,self.args)
     39         self.make_connection()
     40 
     41 
     42     def make_connection(self):
     43         '''连接服务器'''
     44         self.sock = socket.socket()
     45         self.sock.connect((self.options.server,self.options.port))
     46 
     47 
     48 
     49     def verify_args(self,options,args):
     50         '''校验参数合法性'''
     51         if options.username and options.password:
     52             pass
     53         elif options.username is None and options.password is None:
     54             pass
     55         else:
     56             if options.username is None or options.password is None:
     57                 print('Error:username and password must be provided together..')
     58         if options.server and options.port:
     59             if options.port > 0 and options.port < 65535:
     60                 return True
     61             else:
     62                 exit('Err:host port must in 0-65535')
     63 
     64 
     65     def authenticate(self):
     66         '''用户验证'''
     67         if self.options.username:
     68             return self.get_auth_result(self.options.username, self.options.password)
     69         else:
     70             retry_count = 0
     71             while retry_count < 3:
     72                 username = input("username:").strip()
     73                 password = input("password:").strip()
     74                 return self.get_auth_result(username,password)
     75 
     76 
     77 
     78 
     79     def get_auth_result(self,user,password):
     80         '''用户认证'''
     81         data = {'action':'auth',
     82                 'username':user,
     83                 'password':password}
     84 
     85         self.sock.send(json.dumps(data).encode())
     86         response = self.get_response()
     87         if response.get('status_code') == 254:
     88             print("Passed authentication!")
     89             self.user = user
     90             return True
     91         else:
     92             print(data.get('status_msg'))
     93         print('response:',data)
     94 
     95 
     96     def __md5_required(self,cmd_list):
     97         '''检测命令是否需要进行MD5验证'''
     98         if '--md5' in cmd_list:
     99             return True
    100 
    101 
    102     def show_progress(self,total):
    103         '''进度条'''
    104         received_size = 0
    105         current_percent = 0
    106         while received_size < total:
    107             if int((received_size / total) * 100) > current_percent:
    108                 print(">",end='',flush=True)
    109                 current_percent = int((received_size / total) * 100)
    110             new_size = yield
    111             received_size += new_size
    112 
    113 
    114     def send_response(self,status_code,data=None):
    115         '''向服务器端返回数据'''
    116         response = {'status_code': status_code, 'status_msg':STATUS_CODE[status_code]}
    117         if data:
    118             response.update(data)
    119         self.sock.send(json.dumps(response).encode())
    120 
    121 
    122     def get_response(self):
    123         '''得到服务器端回复结果'''
    124         data = self.sock.recv(1024)
    125         data = json.loads(data.decode())
    126         return data
    127 
    128 
    129     def _get(self,cmd_list):
    130         '''下载文件'''
    131         print("get--",cmd_list)
    132         if len(cmd_list) == 1:
    133             print("no filename follows...")
    134             return
    135         data_header = {
    136             'action':'get',
    137             'filename':cmd_list[1]
    138         }
    139         if self.__md5_required(cmd_list):
    140             data_header['md5'] = True
    141 
    142         self.sock.send(json.dumps(data_header).encode())
    143         response = self.get_response()
    144         print(response)
    145         try:
    146             if response["status_code"] == 257:#ready to receive
    147                 self.sock.send(b'1') #send confirmation to server
    148                 base_filename = cmd_list[1].split('/')[-1]
    149                 received_size = 0
    150                 file_obj = open(base_filename,'wb')
    151                 if self.__md5_required(cmd_list):
    152                     md5_obj = hashlib.md5()
    153                     progress = self.show_progress(response['file_size']) #generator
    154                     progress.__next__()
    155                     while received_size < response['file_size']:
    156                         data = self.sock.recv(4096)
    157                         received_size += len(data)
    158                         try:
    159                             progress.send(len(data))
    160                         except StopIteration as e:
    161                             print("100%")
    162                         file_obj.write(data)
    163                         md5_obj.update(data)
    164                     else:
    165                         print("-----file rece done-----")
    166                         file_obj.close()
    167                         md5_val = md5_obj.hexdigest()
    168                         md5_from_server = self.get_response()
    169                         if md5_from_server['status_code'] == 258:
    170                             if md5_from_server['md5'] == md5_val:
    171                                 print("%s 文件一致性校验成功!"% base_filename)
    172                         print(md5_val,md5_from_server)
    173 
    174                 else:
    175                     progress = self.show_progress(response['file_size'])  # generator
    176                     progress.__next__()
    177                     while received_size < response['file_size']:
    178                         data = self.sock.recv(4096)
    179                         received_size += len(data)
    180                         file_obj.write(data)
    181                         try:
    182                             progress.send(len(data))
    183                         except StopIteration as e:
    184                             print("100%")
    185                     else:
    186                         print("-----file rece done-----")
    187                         file_obj.close()
    188             else:
    189                 print(STATUS_CODE[response["status_code"]])
    190         except Exception as e:
    191             base_file_size = os.path.getsize(base_filename)
    192             with open('data\breakpoint', 'wb') as br_po:
    193                 data_header['action'] = 'breakpoint'
    194                 data_header['breakpoint'] = base_file_size
    195                 br_po.write(json.dumps(data_header).encode())
    196 
    197 
    198     def _put(self,cmd_list):
    199         '''上传文件'''
    200         print("put--", cmd_list)
    201         if len(cmd_list) == 1:
    202             print("no filename follows...")
    203             return
    204         data_header = {
    205             'action': 'put',
    206             'filename': cmd_list[1]
    207         }
    208         if self.__md5_required(cmd_list):
    209             data_header['md5'] = True
    210 
    211         self.sock.send(json.dumps(data_header).encode())
    212         if os.path.isfile(cmd_list[1]):
    213             file_obj = open(cmd_list[1], 'rb')
    214             file_size = os.path.getsize(cmd_list[1])
    215             self.send_response(257, data={'file_size': file_size})
    216             self.sock.recv(1)  # 等待服务器端确认
    217             if self.__md5_required(cmd_list):
    218                 md5_obj = hashlib.md5()
    219                 progress = self.show_progress(file_size)  # generator
    220                 progress.__next__()
    221                 for line in file_obj:
    222                     self.sock.send(line)
    223                     try:
    224                         progress.send(len(line))
    225                     except StopIteration as e:
    226                         print("100%")
    227                     md5_obj.update(line)
    228                 else:
    229                     file_obj.close()
    230                     md5_val = md5_obj.hexdigest()
    231                     md5_from_server = self.get_response()
    232                     if md5_from_server['md5'] == md5_val:
    233                             print("%s 文件一致性校验成功!"% cmd_list[1])
    234                     self.send_response(258, {'md5': md5_val})
    235                     print("send file done...")
    236             else:
    237                 progress = self.show_progress(file_size)  # generator
    238                 progress.__next__()
    239                 for line in file_obj:
    240                     self.sock.send(line)
    241                     try:
    242                         progress.send(len(line))
    243                     except StopIteration as e:
    244                         print("100%")
    245                 else:
    246                     file_obj.close()
    247                     print("send file done...")
    248         else:
    249             print(256)
    250 
    251 
    252     def _ls(self,*args,**kwargs):
    253         '''获取当前目录下的所有文件'''
    254         print('ls'.center(30,'-'))
    255         data_header = {
    256             'action': 'ls',
    257         }
    258         self.sock.send(json.dumps(data_header).encode())
    259         ls_val = self.sock.recv(1024)
    260         ls_val = json.loads(ls_val.decode())
    261         for obj in ls_val:
    262             print(obj)
    263 
    264 
    265     def _cd(self,cmd_list):
    266         '''改变工作目录'''
    267         print("cd--", cmd_list)
    268         if len(cmd_list) == 1:
    269             cmd_list.append('')
    270         data_header = {
    271             'action': 'cd',
    272             'path': cmd_list[1]
    273         }
    274         self.sock.send(json.dumps(data_header).encode())
    275         server_path = self.sock.recv(1024)
    276         server_path = json.loads(server_path.decode())
    277         if server_path == 259 :
    278             print("%s >" % cmd_list[1],end='')
    279 
    280 
    281     def _breakpoint(self,*args,**kwargs):
    282         '''断点续传'''
    283         with open('data\breakpoint', 'rb') as br_po:
    284             data_header = json.loads(br_po.read().decode())
    285             br_po.close()
    286         if data_header:
    287             print(data_header)
    288             self.sock.send(json.dumps(data_header).encode())
    289             response = self.get_response()
    290             try:
    291                 if response["status_code"] == 257:  # ready to receive
    292                     self.sock.send(b'1')  # send confirmation to server
    293                     base_filename = data_header['filename'].split('/')[-1]
    294                     received_size = data_header['breakpoint']
    295                     file_obj = open(base_filename, 'ab')
    296                     file_obj.seek(data_header['breakpoint'])
    297                     if self.__md5_required(data_header):
    298                         md5_obj = hashlib.md5()
    299                         progress = self.show_progress(response['file_size'])  # generator
    300                         progress.__next__()
    301                         while received_size < response['file_size']:
    302                             data = self.sock.recv(4096)
    303                             received_size += len(data)
    304                             try:
    305                                 progress.send(len(data))
    306                             except StopIteration as e:
    307                                 print("100%")
    308                             file_obj.write(data)
    309                             md5_obj.update(data)
    310                         else:
    311                             print("-----file rece done-----")
    312                             file_obj.close()
    313                             md5_val = md5_obj.hexdigest()
    314                             md5_from_server = self.get_response()
    315                             if md5_from_server['status_code'] == 258:
    316                                 if md5_from_server['md5'] == md5_val:
    317                                     print("%s 文件一致性校验成功!" % base_filename)
    318                                     with open('data\breakpoint', 'wb') as br_po:
    319                                         br_po.write()
    320                             print(md5_val, md5_from_server)
    321 
    322 
    323 
    324                     else:
    325                         progress = self.show_progress(response['file_size'])  # generator
    326                         progress.__next__()
    327                         while received_size < response['file_size']:
    328                             data = self.sock.recv(4096)
    329                             received_size += len(data)
    330                             file_obj.write(data)
    331                             try:
    332                                 progress.send(len(data))
    333                             except StopIteration as e:
    334                                 print("100%")
    335                         else:
    336                             print("-----file rece done-----")
    337                             file_obj.close()
    338                             with open('data\breakpoint', 'wb') as br_po:
    339                                 br_po.write()
    340             except Exception as e:
    341                 base_file_size = os.path.getsize(base_filename)
    342                 with open('data\breakpoint', 'wb') as br_po:
    343                     data_header['breakpoint'] = base_file_size
    344                     br_po.write(json.dumps(data_header).encode())
    345         else:print('There is no need to transfer files..')
    346 
    347 
    348     def _helps(self,*args,**kwargs):
    349         '''帮助信息'''
    350         helps = '''
    351             get 文件名     #下载文件
    352             put 文件名     #上传文件
    353             ls             #获取当前目录下的所有文件
    354             cd             #改变工作目录
    355             breakpoint     #断点续传'''
    356         print(helps)
    357 
    358 
    359     def interactive(self):
    360         '''根据命令分配函数'''
    361         if self.authenticate():
    362             print('---start interactive iwth u...(helps  帮助信息)')
    363             while True:
    364                 choice = input("[%s]:" % self.user).strip()
    365                 if len(choice) == 0: continue
    366                 cmd_list = choice.split()
    367                 if hasattr(self, "_%s" % cmd_list[0]):
    368                     func = getattr(self, "_%s" % cmd_list[0])
    369                     func(cmd_list)
    370                 else:
    371                     print("Invalid cmd")
    372 
    373 
    374 
    375 if __name__ == '__main__':
    376     ftp = FTPClient()
    377     ftp.interactive()
    client端
  • 相关阅读:
    zTree根据json选中节点,并且设置其他节点不可选
    点击一次按钮,发生多次ajax请求
    sublimeText3 中配置sass环境,并将编译后文件保存到指定文件夹
    MD5加密
    c# Http请求之HttpClient
    xml与object 之间的ORM
    wpf和winform的那点区别
    c# http请求ajax页面
    c# https请求
    python爬虫框架Pyspider初次接触
  • 原文地址:https://www.cnblogs.com/liyongbin/p/7196528.html
Copyright © 2011-2022 走看看