• FTPserver


    客户端代码:

    import os
    import hashlib
    
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    FILE_PATH = os.path.join(BASE_DIR, 'donwload')
    
    def make_md5_on_file(file_path):
        '''给文件制作md5  每次都要打开文件,要想办法保存到一个位置,当文件发生修改时更新这个md5'''
        m = hashlib.md5()
        with open(file_path, 'rb') as f:
            for line in f:
                bytes_str = line
                m.update(bytes_str)
            md5value = m.hexdigest()
            return md5value
    import socket
    import optparse
    import json
    import struct
    import os
    import sys
    import shelve
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    from conf import settings
    
    
    class FTPClient(object):
        address_family = socket.AF_INET
        socket_type = socket.SOCK_STREAM
        allow_reuse_address = True
        max_pack_size = 8192
        request_queue_size = 5
        coding = 'utf-8'
        donwload_dir = settings.FILE_PATH
    
        def __init__(self, connect=True):
            ''' elf.options 这是这个模块生成的一个字典 self.args  这是用户输入的命令。和sys.argv 差不多
                如果用户按照规则输入,那么相应的值 就会在字典中显示, 不按规则输入的值,就放倒了列表中'''
            parser = optparse.OptionParser()
            parser.add_option("-s", "--server", dest='server', help="ftp server ip_addr")
            parser.add_option("-P", "--port", type="int", dest="port", help="ftp server port")
            parser.add_option("-u", "--username", dest="username", help="username info")
            parser.add_option("-p", "--password", dest="password", help="password info")
            self.options, self.args = parser.parse_args()
            self.current_dir = None
            self.argv_verification()  # 判断合法性
            self.socket = self.make_connection()  # 建立连接
            self.shelve_obj = shelve.open('defect_file')  # 得到下载时shelve文件对象
            self.shelve_load_obj = shelve.open('unfinish_file')
            if connect:
                try:
                    self.client_connect()
                except Exception:
                    self.client_close()
                    exit('以断开连接')
    
        def argv_verification(self):
            '''判断用户输入的合法性'''
            if not self.options.server or not self.options.port:
                exit('必须提供,ip 和 端口')
    
        def make_connection(self):
            '''由构造函数调用生成 socket 对象'''
            self.socket = socket.socket(self.address_family, self.socket_type)
            return self.socket
    
        def client_connect(self):
            '''由构造函数直接调用,激活客户端,连接服务端'''
            self.socket.connect((self.options.server, self.options.port))  #
    
        def client_close(self):
            '''由构造函数调用,关闭客户端'''
            self.socket.close()
    
        def auth(self):
            '''输入账户名,密码。服务端验证完成后,根据接收到的状态码,返回 Ture or False'''
            count = 0
            while count < 3:
                username = input('username:').strip()
                if not username: continue
                self.current_dir = '\' + username
                pwd = input('password:').strip()
                cmd = {
                    'action_type': 'auth',
                    'username': username,
                    'password': pwd
                }
    
                self.send_head(cmd)
                head_dic = self.recv_head()
                if head_dic['status_code'] == 200:
    
                    return True
                else:
                    count += 1
                    print(head_dic['status_msg'])
                    continue
    
        def send_head(self, cmd):
            '''发送客户端的报头,'''
            client_head_bytes = json.dumps(cmd).encode(self.coding)
            client_head_len = struct.pack('i', len(client_head_bytes))
            self.socket.send(client_head_len)
            self.socket.send(client_head_bytes)
    
        def recv_head(self):
            '''接收服务端发来的报头'''
            obj = self.socket.recv(4)
            header_size = struct.unpack('i', obj)[0]
            header_json = self.socket.recv(header_size).decode(self.coding)
            header_dict = json.loads(header_json)
            return header_dict
    
        def send_file(self, file_path, head_dic, sercver_dir, md5val, send_size=0):
            '''发送文件'''
            self.shelve_load_obj[file_path] = [head_dic, sercver_dir, md5val]
            genertor = self.progress_bar(head_dic['filesize'])
            genertor.__next__()
            with open(file_path, 'rb') as f:
                f.seek(send_size)
                for line in f:
                    self.socket.send(line)
                    send_size += len(line)
                    genertor.send(send_size)
                else:
                    del self.shelve_load_obj[file_path]
                    print('数据发送成功')
            header_dict = self.recv_head()
            print(header_dict['status_msg'])
    
        def recv_file(self, file_path, file_size, md5_value, filename, recv_size=0):
            '''接收服务端文件数据, 并 保存所有文件信息, 防止程序中断时,可以进行续传,
            文件正常传完, 删除文件描述信息, 并改名'''
            file_abs_path = os.path.join(r'%s\%s' % (self.current_dir, filename))  # 拼接客户端在那个位置下载的文件
            self.shelve_obj[file_abs_path] = [file_size, filename+'.download']  # 以绝对路径为键,保存文件大小的值
    
            with open(file_path, 'ab') as f:
                while recv_size < file_size:
                    line = self.socket.recv(self.max_pack_size)
                    f.write(line)
                    recv_size += len(line)
                    progres(recv_size, file_size)  # 进度条
            md5value = settings.make_md5_on_file(file_path)
            if md5value == md5_value:
                del self.shelve_obj[file_abs_path]
                if filename not in os.listdir(self.donwload_dir):
                    os.renames(file_path, os.path.join(self.donwload_dir, filename))
                else:
                    print('文件重名,未覆盖!', end='')
                print()
    
        def put(self, *args):
            '''上传文件'''
            cmd = args[0]
            filename = args[1]
            sercver_dir = '%s\%s' % (self.current_dir, filename)
            if not os.path.isfile(os.path.join(self.donwload_dir, filename)):
                print('file %s 不在donwload文件中' % filename)
                return
            else:
                filesize = os.path.getsize(os.path.join(self.donwload_dir, filename))
                md5value = settings.make_md5_on_file(os.path.join(self.donwload_dir, filename))
                head_dic = {'action_type': cmd, 'filesize': filesize, 'filename': filename, 'md5value': md5value}
                file_path = os.path.join(self.donwload_dir, filename)
                self.send_head(head_dic)
                self.send_file(file_path, head_dic, sercver_dir, md5value)
    
        def re_put(self, file_path, load_head_dic, sercver_dir, md5value):
            server_head_dic = self.recv_head()
            received_size = server_head_dic['file_size']
            self.send_file(file_path, load_head_dic, sercver_dir, md5value, send_size=received_size)
    
        def progress_bar(self, total_size):
            '''生成器 方式的, 进度条展示'''
            current_percent = 0
            last_percent = 0
            while True:
                recvived_size = yield current_percent
                current_percent = int(recvived_size / total_size * 100)
                if current_percent > last_percent:
                    print("#" * int(current_percent/2) + "{percent}%".format(percent=current_percent), flush=True, end='
    ')
                    last_percent = current_percent
    
        def get(self, *args):
            '''下载文件'''
            cmd = args[0]
            filename = args[1]
            client_head_dic = {'action_type': cmd, 'filename': filename}
            self.send_head(client_head_dic)
            server_head_dic = self.recv_head()
    
            if server_head_dic['status_code'] == 300:
                print(server_head_dic['status_msg'])
                return
    
            file_path = os.path.join(self.donwload_dir, '%s.download' % filename)  # 存放文件路径
            total_size = server_head_dic['filesize']  # 文件最大大小
            md5_val = server_head_dic['md5value']  # 得到服务端发来的 MD5 值
            self.recv_file(file_path, total_size, md5_val, filename)
    
        def re_get(self, head_dic):
            '''由程序自检之后,用户选择 是否进行续传。 如果续传 调用该方法。
            发送报头:
            1. 检测 已收到文件大小
            2. 编辑报头,使用 self.socket.send() 发送报头
            3. 接收文件,'''
            self.send_head(head_dic)
            server_head_dic = self.recv_head()
            if server_head_dic['status_code'] == 300:
                print(server_head_dic['status_msg'])
                return
            file_path = os.path.join(self.donwload_dir, head_dic['filename'])  # 存放文件路径
            total_size = head_dic['total_size']
            md5_val = server_head_dic['md5value']  # 得到服务端发来的 MD5 值
            self.recv_file(file_path, total_size, md5_val, server_head_dic['filename'], head_dic['received_file_size'])
    
        def ls(self, *args):
            '''显示当前目录下的文件'''
            cmd = args[0]
            client_head_dic = {'action_type': cmd}
            self.send_head(client_head_dic)
            server_head_dic = self.recv_head()
            if server_head_dic['status_code'] == 0:
                print(server_head_dic['dir_info'])
            if server_head_dic['status_code'] == 100:
                print(server_head_dic['dir_info'])
    
        def cd(self, *args):
            '''切换目录'''
            cmd = args[0]
            dirname = args[1]
            if dirname != '.':
                client_head_dic = {'action_type': cmd, 'dirname': dirname}
                self.send_head(client_head_dic)
                server_head_dic = self.recv_head()
                if server_head_dic['status_code'] == 400:
                    print(server_head_dic['status_msg'])
                elif server_head_dic['status_code'] == 401:
                    print(server_head_dic['status_msg'])
                    self.current_dir = server_head_dic['dirn']
                elif server_head_dic['status_code'] == 0:
                    self.current_dir = server_head_dic['dirn']
            else:
                print('输入错误')
                return
    
        def help_msg(self, *args):
            msg = '''command error!!!
            Correct format:
            get filename 下载文件
            put filename 上传文件
            ls  显示当前所在目录下的文件和子目录
            cd dirname 切换到那个目录下'''
            print(msg)
    
        def unfinished_file_check(self):
            if not self.shelve_obj:
                print('没有未接收的文件'.center(30, '-'))
                return
            for index, abs_file in enumerate(self.shelve_obj.keys()):
                self.received_file_size = os.path.getsize(os.path.join(self.donwload_dir, self.shelve_obj[abs_file][1]))
                print('文件编号 %d  服务器文件保存地址 %s  文件总大小%s  文件名%s  已收到文件大小%s' %
                      (index, abs_file, self.shelve_obj[abs_file][0], self.shelve_obj[abs_file][1], self.received_file_size))
            while True:
                choice = input('选择想要继续下载的文件编号 [back] 退出:').strip()
                if not choice: continue
                if choice == 'back': break
                if choice.isdigit():
                    choice = int(choice)
                    if choice >=0 and choice <= index:
                        selected_file = list(self.shelve_obj.keys())[choice]  # 通过索引,拿到想要的那个文件的 key
                        total_size = self.shelve_obj[selected_file][0]  # 文件总大小
                        file_name = self.shelve_obj[selected_file][1]  # 文件名
                        size = self.received_file_size  # 已收到的文件大小
                        head_dic = {'action_type': 're_get', 'abs_file': selected_file,  'total_size': total_size,
                                    'received_file_size': size, 'filename': file_name}
                        self.re_get(head_dic)
    
        def unsend_by_file_check(self):
            if not self.shelve_load_obj:
                print('没有未上传完整的文件'.center(30, '-'))
                return
            for index, abs_file in enumerate(self.shelve_load_obj.keys()):
                print('%s %s %s' % (index, abs_file, self.shelve_load_obj[abs_file]))
            while True:
                choice = input('选择想要继续上传的文件编号 [back] 退出:').strip()
                if not choice: continue
                if choice == 'back': break
                if choice.isdigit():
                    choice = int(choice)
                    if choice >= 0 and choice <= index:
                        # file_path, head_dic, sercver_dir, md5val
                        file_path = list(self.shelve_load_obj.keys())[choice]
                        filesize = self.shelve_load_obj[file_path][0]['filesize']
                        load_head_dic = self.shelve_load_obj[file_path][0]
                        sercver_dir = self.shelve_load_obj[file_path][1].strip('\')
                        md5value = self.shelve_load_obj[file_path][2]
                        head_dic = {'action_type': 're_put', 'abs_file': sercver_dir, 'md5value': md5value, 'filesize': filesize}
                        self.send_head(head_dic)
                        self.re_put(file_path, load_head_dic, sercver_dir, md5value)
    
        def interactive(self):  # 交互函数
            '''处理 与 服务端 的所有交互,解析用户输入的指令'''
            if self.auth():
                self.unfinished_file_check()
                self.unsend_by_file_check()
                while True:
                    inp = input('[%s] Q退出:' % self.current_dir).strip()
                    if not inp: continue
                    cmds = inp.split()
                    if inp != 'Q':
                        if hasattr(self, cmds[0]):
                            func = getattr(self, cmds[0])
                            func(*cmds)
                        else:
                            self.help_msg()
                            continue
                    else:
                        self.shelve_obj.close()
                        self.client_close()
                        exit('谢谢使用')
    
        def make_dir(self, *args):
            '''在自己的目录下,创建文件夹'''
            print('在自己的目录下,创建文件夹')
    
    def humanbytes(B):
        '''这传代码 抄来的  T_T '''
        B = float(B)
        KB = float(1024)
        MB = float(KB ** 2)  # 1,048,576
        GB = float(KB ** 3)  # 1,073,741,824
        TB = float(KB ** 4)  # 1,099,511,627,776
    
        if B < KB:
            return '{0} {1}'.format(B,'Bytes' if 0 == B > 1 else 'Byte')
        elif KB <= B < MB:
            return '{0:.2f} KB'.format(B/KB)
        elif MB <= B < GB:
            return '{0:.2f} MB'.format(B/MB)
        elif GB <= B < TB:
            return '{0:.2f} GB'.format(B/GB)
        elif TB <= B:
            return '{0:.2f} TB'.format(B/TB)
    
    def progres(recv_size, total_size):
        bar_length = 50
        percent = float(recv_size) / float(total_size)
        hashes = '=' * int(percent * bar_length)
        spaces = ' ' * (bar_length - len(hashes))
    
        sys.stdout.write("
    传输中: [%s] %d%%  %s/%s " % (hashes + spaces, percent * 100,
                                                       humanbytes(recv_size), humanbytes(total_size)))
        sys.stdout.flush()
    
    
    if __name__ == '__main__':
        client = FTPClient()
        client.interactive()
    client.py

    服务端代码:

    import os
    import sys
    
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    # 入口程序必须先 指定 基础目录。以便于其余的调用程序,可以通过这个路径,进行相对的导入
    sys.path.append(BASE_DIR)  # 将基础目录添加到,路径列表中
    
    if __name__ == '__main__':
        from core import management
        # print()
        # ['luffy_server.py', 'start']
        # sys.argv 把用户终端输入的命令,拿到并把拿到的列表,交给 解析命令的类。传给__init__了
       #['luffy_server.py', 'start']
    argv_parser = management.ManagementTool(sys.argv) argv_parser.execute()
    import os
    import socket
    
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    HOST = "127.0.0.1"  #  服务端IP 用于服务端进行绑定使用
    PORT = 8080  # 服务端 端口
    
    ADDRESS_FAMILY = socket.AF_INET
    SOCKET_TYPE = socket.SOCK_STREAM
    ALLOW_REUSE_ADDRESS = True
    MAX_PACKET_SIZE = 8192
    MAX_SOCKET_LISTEN = 5
    CODING = 'utf-8'  # 指定编码类型
    USER_HOME_DIR = os.path.join(BASE_DIR, 'home')
    
    ACCOUNT_FILE = os.path.join(BASE_DIR, 'conf', 'accounts.ini')
    settings
    import hashlib
    import configparser
    from .import settings
    
    def make_md5_on_file(file_path):
        '''给文件制作md5  每次都要打开文件,要想办法保存到一个位置,当文件发生修改时更新这个md5'''
        m = hashlib.md5()
        with open(file_path, 'rb') as f:
            for line in f:
                bytes_str = line
                m.update(bytes_str)
            md5value = m.hexdigest()
            return md5value
    
    def load_all_user_info():
        '''由FTPserver调用,加载所有的用户数据到内存'''
        confing = configparser.ConfigParser()
        confing.read(settings.ACCOUNT_FILE)
        return confing
    conf_tool.py
    from core import main
    
    class ManagementTool(object):
        '''负责对 用户输入的指令,进行解析。并调用相应的模块处理'''
        def __init__(self, sys_argv):
            self.sys_argv = sys_argv
            self.verification()
    
        def verification(self):
            '''由构造函数调用 验证用户输入的指令是否合法,如果不合法。打印帮助信息'''
            if len(self.sys_argv) < 2:  # sys.argv 列表中默认会带上文件名,所以长度必须不能小于2
                self.help_msg()
            cmd = self.sys_argv[1]
            if not hasattr(self, cmd):
                print('无效语法')
                self.help_msg()
    
        def help_msg(self):
            msg = '''
            start       start FTP server
            stop        stop FTP server
            restart     restart FTP server
            createuser  username  create a ftp user
            其余功能还没扩展呢'''
            exit(msg)  # 如果命令输入的是错误的,就退出程序。因为 如果继续向后走的话,会因为没有这个命令报错。
            # 虽然可以,加上循环。让用户继续输入。不过 再来一次就好了。没必要那么麻烦
    
        def execute(self):
            '''进行解析并执行指令,写在这里可以进行扩展'''
            cmd = self.sys_argv[1]
            func = getattr(self, cmd)
            func()   # 这里并没有传参数,因为sys.argv 是构造函数中的,相当于类中的一个全局变量。
            # 其余函数 直接调用就好了,不需要还要在这里传参数
    
        def start(self):
            '''启动FTP server'''
            server = main.FTPServer(self)  # FTPServer 有可能用到当前这个程序的一些东西,那么就把实例本身
            server.run_forever()            # 当作一个参数 传给FTPServer  那就可以在FTPServer中使用这个类中的属性了
    
        def stop(self):
            '''这是停止服务'''
            print('停止服务了')
    
        def restart(self):
            '''重新启动服务器'''
            print('重新启动服务器')
    
        def createuser(self):
            '''管理员创建用户使用的'''
            print('管理员专用')
    management.py
      1 import socket
      2 import json
      3 import hashlib
      4 import struct
      5 import os
      6 import subprocess
      7 from conf import settings
      8 from conf import config_tool
      9 
     10 
     11 class FTPServer(object):
     12     '''处理与客户端所有的交互的 socket server
     13     所需要的参数,从settings 和 实例化时 传进来'''
     14     address_family = settings.ADDRESS_FAMILY
     15     socket_type = settings.SOCKET_TYPE
     16     allow_reuse_address = settings.ALLOW_REUSE_ADDRESS  # 是否重用端口开关 默认 Fales
     17     max_packet_size = settings.MAX_PACKET_SIZE  # 最大传输流量8192
     18     coding = settings.CODING  # utf-8
     19     request_queue_size = settings.MAX_SOCKET_LISTEN  # 最大挂起数量5
     20     server_dir = settings.USER_HOME_DIR  # 总家目录
     21 
     22     STATUS_CODE = {
     23         0: 'normal ',
     24         100: 'ls Error info',
     25         101: 'current dir has no file at all',
     26         200: 'Username Password Authentication Successful!',
     27         201: 'wrong username or password',
     28         300: 'The file was not find',
     29         301: 'find the file',
     30         302: 'The server did not receive the complete data',
     31         303: 'The server receive the complete data',
     32         400: 'The dirname was not find',
     33         401: 'Has entered this directory',
     34         500: "It's already on the top floor"
     35     }
     36 
     37     def __init__(self, management_instance, bind_and_acttivate=True):  # 在management类中start的位置,将management的实例传进来
     38         '''构造函数,可扩展 不可覆盖'''
     39         self.management_instance = management_instance  # 类的构造函数中,接收这个参数,这样就能够使用到传进来的实例的对象中的属性
     40         self.socket = socket.socket(self.address_family, self.socket_type)
     41         self.config_obj = config_tool.load_all_user_info()  #
     42         if bind_and_acttivate:
     43             try:
     44                 self.server_bind()
     45                 self.server_activate()
     46             except Exception:
     47                 self.server_close()
     48 
     49     def server_bind(self):
     50         """由构造函数调用以绑定套接字"""
     51         if self.allow_reuse_address:
     52             self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     53         self.socket.bind((settings.HOST, settings.PORT))
     54         self.server_address = self.socket.getsockname()
     55 
     56     def server_activate(self):
     57         """由构造函数调用以激活服务器 """
     58         self.socket.listen(self.request_queue_size)
     59 
     60     def get_request(self):
     61         """从套接字获取请求和客户机地址。 """
     62         return self.socket.accept()
     63 
     64     def server_close(self):
     65         """调用以清理服务器。"""
     66         self.socket.close()
     67 
     68     def close_request(self):
     69         """调用以清除单个请求"""
     70         self.request.close()
     71 
     72     def run_forever(self):
     73         '''启动socket server 运行到天荒地老'''
     74         print('starting luffyFTP server on %s:%s'.center(50, '-') % (settings.HOST, settings.PORT))
     75         while True:
     76             try:
     77                 self.request, self.client_addr = self.get_request()
     78                 print('from client %s' % (self.client_addr,))
     79                 # print(self.request, self.cline_addr)
     80                 self.handle()
     81             except Exception:
     82                 print('客户端 %s 断开连接' % (self.client_addr,))
     83                 self.close_request()
     84 
     85     def handle(self):
     86         '''接收客户端发来的报头 解析之后 进行相应的操作'''
     87         while True:
     88             raw_data = self.request.recv(4)
     89             if not raw_data:
     90                 print('client %s disconnection' % self.client_addr)
     91                 del self.request, self.client_addr
     92                 break
     93             data_len = struct.unpack('i', raw_data)[0]
     94             date_json = self.request.recv(data_len).decode(self.coding)
     95             data_dic = json.loads(date_json)
     96             action_type = data_dic.get('action_type')
     97             if action_type:  # 不能为空
     98                 if hasattr(self, "_%s" % action_type):
     99                     func = getattr(self, "_%s" % action_type)
    100                     func(data_dic)
    101 
    102     def send_response(self, status_code, *args, **kwargs):
    103         '''打包发送状态码消息给客户端'''
    104         data = kwargs
    105         data['status_code'] = status_code
    106         data['status_msg'] = self.STATUS_CODE[status_code]
    107         bytes_data = json.dumps(data).encode('utf-8')
    108         head_struct = struct.pack('i', len(bytes_data))
    109 
    110         self.request.send(head_struct)   # 这里时通信循环干的事情了,一定要是self.request
    111         self.request.send(bytes_data)
    112 
    113     def authentication(self, username, password):
    114         '''对用户名密码进行验证'''
    115         if username in self.config_obj:
    116             _password = self.config_obj[username]['password']
    117             md5_obj = hashlib.md5()
    118             md5_obj.update(password.encode('utf-8'))
    119             if md5_obj.hexdigest() == _password:
    120                 return True
    121 
    122     def _auth(self, data):
    123         '''处理用户认证请求'''
    124         if self.authentication(data.get('username'), data.get('password')):
    125             self.home_dir = os.path.join(self.server_dir, data.get('username'))
    126             self.userhome_dir = os.path.join(self.server_dir, data.get('username'))
    127             self.send_response(status_code=200,)
    128         else:
    129             self.send_response(status_code=201)
    130 
    131     def _put(self, data):
    132         '''用户进行上传,'''
    133         file_path = os.path.normpath(os.path.join(self.userhome_dir, data['filename']))
    134         filesize = data['filesize']
    135         cilent_md5 = data['md5value']
    136         result = self.recv_file(file_path, cilent_md5, filesize)
    137         if result:
    138             self.send_response(status_code=303)
    139         else:
    140             self.send_response(status_code=302)
    141 
    142     def _get(self, data):
    143         '''用户进行下载'''
    144         file_path = os.path.normpath(os.path.join(self.userhome_dir, data['filename']))
    145         if not os.path.isfile(file_path):
    146             self.send_response(status_code=300)
    147         else:
    148             filesize = os.path.getsize(file_path)
    149             md5value = config_tool.make_md5_on_file(file_path)
    150             self.send_response(status_code=301, filesize=filesize, md5value=md5value, filename=data['filename'])
    151             self.send_file(file_path)
    152 
    153     def recv_file(self, file_path, cilent_md5, filesize, recv_size=0):
    154         '''接收文件,需要文件存放路径,MD5值,文件大小, 已接受的文件大小'''
    155 
    156         with open(file_path, 'ab') as f:
    157             while recv_size < filesize:
    158                 recv_data = self.request.recv(self.max_packet_size)
    159                 if not recv_data: break
    160                 f.write(recv_data)
    161                 recv_size += len(recv_data)
    162         md5value = config_tool.make_md5_on_file(file_path)
    163         if md5value == cilent_md5:
    164             return True
    165 
    166     def send_file(self, file_path, send_size=0):
    167         with open(file_path, 'rb') as f:
    168             f.seek(send_size)
    169             for line in f:
    170                 self.request.send(line)
    171 
    172     def _re_get(self, data):
    173         abs_file = data['abs_file'].strip('\')
    174         file_path = os.path.normpath(os.path.join(settings.USER_HOME_DIR, abs_file))
    175         if not os.path.isfile(file_path):
    176             self.send_response(status_code=300)
    177         if os.path.getsize(file_path) != data['total_size']:
    178             self.send_response(status_code=300)
    179         else:
    180             md5value = config_tool.make_md5_on_file(file_path)
    181             self.send_response(status_code=301, md5value=md5value, filename=os.path.basename(file_path))
    182             self.send_file(file_path, send_size=data['received_file_size'])
    183 
    184     def _re_put(self, data):
    185         '''用于用户上传,没有传完整,续传使用'''
    186         abs_file = data['abs_file'].strip('\')
    187         file_path = os.path.normpath(os.path.join(settings.USER_HOME_DIR, abs_file))
    188         md5value = data['md5value']
    189 
    190         if not os.path.isfile(file_path):
    191             self.send_response(status_code=300)
    192         else:
    193             received_file_size = os.path.getsize(file_path)  # 返回给客户端,已经收到了多少字节
    194             self.send_response(status_code=301, file_size=received_file_size)
    195             filesize = data['filesize'] - received_file_size
    196             result = self.recv_file(file_path, md5value, filesize)
    197             if result:
    198                 self.send_response(status_code=303)
    199             else:
    200                 self.send_response(status_code=302)
    201 
    202     def _ls(self, data):
    203         '''给客户端显示当前文件下有哪些内容'''
    204         cmd_boj = subprocess.Popen('dir %s' % self.userhome_dir, shell=True, stdout=subprocess.PIPE,
    205                          stderr=subprocess.PIPE)
    206         stdout = cmd_boj.stdout.read()
    207         stderr = cmd_boj.stderr.read()
    208         cmd_result = (stdout + stderr).decode('GBK')
    209         if not cmd_result:
    210             self.send_response(status_code=101)
    211         else:
    212             self.send_response(status_code=0, dir_info=cmd_result)
    213 
    214     def _cd(self, data):
    215         '''进入用户想要进入的目录当中'''
    216         dirname = data['dirname']
    217         if not dirname.startswith('.'):
    218             if os.path.isdir(os.path.join(self.userhome_dir, dirname)):
    219                 self.userhome_dir = os.path.join(self.userhome_dir, dirname)
    220                 self.client_dir = self.userhome_dir.replace(settings.USER_HOME_DIR, '')
    221                 self.send_response(status_code=401, dirn=self.client_dir)
    222             else:
    223                 self.send_response(status_code=400)
    224         else:
    225             li = dirname.split('\')
    226             count = 0
    227             while count < len(li):
    228                 '''循环 如果 当前路径 已经到用户的家目录,就返回500 已经到达最顶层'''
    229                 if self.userhome_dir == self.home_dir:
    230                     self.send_response(status_code=500)
    231                 else:
    232                     self.userhome_dir = os.path.dirname(self.userhome_dir)
    233                     self.client_dir = self.userhome_dir.replace(settings.USER_HOME_DIR, '')
    234                     self.send_response(status_code=0, dirn=self.client_dir)
    235                 count += 1
    236 
    237     def _make_dir(self):
    238         '''创建用户想要创建的文件夹'''
    239         print('创建用户想要创建的文件夹')
    main.py
  • 相关阅读:
    数据结构矩阵问题总结
    数据结构:二维ST表
    mysql--时区表问题(Windows环境下)
    mysql--基本命令
    Django2.0--创建缓存表
    git--基本命令
    阿里云主机--重置系统后的登录问题
    链表中倒数第K个结点
    从尾到头打印链表
    替换空格
  • 原文地址:https://www.cnblogs.com/chengege/p/10345901.html
Copyright © 2020-2023  润新知