예제 #1
0
    def handle(self):
        """
        服务端处理主方法
        self.request 是客户端的socket对象
        :return:
        """
        print(self.client_address)
        status = self.request.recv(8096)  # 接收客户端的操作
        if status == b"2003":
            self.request.close()
            return
        # 从字典中取出方法
        func_str = settings.status.get(status.decode('utf8'))
        td = TransferDic(self.request)
        # 接收客户端的信息
        user_info = td.accept_packget_dict()

        action = Action()
        if hasattr(action, func_str):
            func = getattr(action, func_str)
            user_info = func(self.request, user_info)
            if user_info:
                # 登陆成功之后的操作
                tcp_server = FtpServer(self.request, user_info)
                tcp_server.run()
예제 #2
0
 def login(self, socket, user_info):
     """登录相关"""
     username = user_info['username']
     password = user_info['password']
     # 读取userinfo文件,查看用户和密码是否正确
     td = TransferDic(socket)
     for user in HandleDb.read_file(settings.user_path):
         userinfo_list = user.split("|")
         user = userinfo_list[0].strip()
         passwd = userinfo_list[1].strip()
         disk_quota = userinfo_list[2].strip()
         passwd_md5 = self.ep.md5_encry(password)
         if username == user and passwd_md5 == passwd:
             # 如果已经登录成功就返回code
             td.send_packget_dict({"user_code": "3003"})
             return (username, disk_quota)
     else:
         td.send_packget_dict({"user_code": "3004"})
         return
예제 #3
0
 def register(self, socket, user_info):
     """注册相关"""
     username = user_info['username']
     password = user_info['password']
     # 读取userinfo文件,查看用户是否已经被注册
     td = TransferDic(socket)
     for user in HandleDb.read_file(settings.user_path):
         userinfo_list = user.split("|")
         if username == userinfo_list[0].strip():
             # 如果已经注册了就返回code
             td.send_packget_dict({"user_code": "3001"})
             return
     else:
         passwd = self.ep.md5_encry(password)
         user_msg = "%s|%s|%s" % (username, passwd, settings.disk_quotas)
         # 将用户信息写入文件
         HandleDb.write_file(settings.user_path, user_msg)
         # 帮用户以用户名创建空文件夹
         userfile_path = os.path.join(settings.home_path, username)
         os.mkdir(userfile_path)
         td.send_packget_dict({"user_code": "3002"})
         return
예제 #4
0
 def __init__(self, socket, user_info):
     self.request = socket
     self.username = user_info[0]
     self.disk_quota = int(user_info[1]) * 1024 * 1024
     self.td = TransferDic(self.request)
     self.user_dir = os.path.join(settings.home_path, self.username)
예제 #5
0
class FtpServer():
    """文件上传下载服务端"""
    address_family = socket.AF_INET
    socket_type = socket.SOCK_STREAM  # tcp流类型
    allow_reuse_address = False
    max_packet_size = 8192
    coding = 'utf-8'
    request_queue_size = 5  # 队列最长数量

    def __init__(self, socket, user_info):
        self.request = socket
        self.username = user_info[0]
        self.disk_quota = int(user_info[1]) * 1024 * 1024
        self.td = TransferDic(self.request)
        self.user_dir = os.path.join(settings.home_path, self.username)

    def server_close(self):
        self.request.close()

    def close_request(self, request):
        request.close()

    def run(self):
        """服务端处理主方法"""
        while True:
            try:
                head_dic = self.td.accept_packget_dict()
                if not head_dic: return
                action = head_dic['action']
                if hasattr(self, action):
                    func = getattr(self, action)
                    func(head_dic)
            except Exception:
                return

    def file_md5_pro(self, file_path):
        """
        计算文件的md5值并返回
        :param file_path:文件路径
        :return:
        """
        md5 = hashlib.md5()
        with open(file_path, "rb") as f:
            for line in f:
                md5.update(line)
        return md5.hexdigest()

    def progress_bar(self, new_size, sum_size):
        """根据每次输入的大小判断目前的百分比"""
        bar = int(new_size / sum_size * 100)
        bar_num = bar // 3
        print("\r%s|进度为:%s%%" % ("#" * bar_num, bar), end="")

    def send_file(self, file_seek, filename, filesize):
        send_size = file_seek
        # 最后发送需要传输的文件
        with open(filename, "rb") as f:
            f.seek(file_seek)
            for line in f:
                self.request.send(line)
                send_size += len(line)
                self.progress_bar(send_size, filesize)
            print()
        return send_size

    def accept_file(self, file_md5_path, old_filesize, filesize):
        """接收客户端发送来的文件内容"""
        f = open(file_md5_path, "ab")
        recv_size = old_filesize  # 记录读取文件的大小
        while recv_size < filesize:
            recv_data = self.request.recv(self.max_packet_size)
            self.file_md5.update(recv_data)
            f.write(recv_data)
            f.flush()  # 主动将内存数据写入硬盘
            recv_size += len(recv_data)
            self.progress_bar(recv_size, filesize)
        print()
        f.close()
        return recv_size

    def put(self, args):
        """实现文件上传"""
        print(args)
        old_file_md5 = args['file_md5']
        filesize = args['filesize']
        filename = args['filename']
        user_dir_exist_size = HandleFile.get_file_size(self.user_dir)
        user_dir_exist_allsize = int(user_dir_exist_size) + int(filesize)
        if user_dir_exist_allsize > self.disk_quota:
            print("目前已经使用了%sMB,总共%sMB容量" %
                  (user_dir_exist_size // 1024 // 1024,
                   self.disk_quota // 1024 // 1024))
            self.td.send_packget_dict({"code": "1011"})
            return
        else:
            print("配额充足,允许上传")
            self.td.send_packget_dict({"code": "1012"})
        file_md5_path = os.path.normpath(
            os.path.join(self.user_dir, old_file_md5))
        file_name_path = os.path.normpath(os.path.join(self.user_dir,
                                                       filename))
        # 判断文件是否之前存在
        self.file_md5 = hashlib.md5()  # 需要计算文件的md5值,保证上传的完整性
        if not os.path.exists(file_md5_path):
            old_filesize = 0
            response = {'code': 1001}  # 1001则代表是新文件
            self.request.sendall(json.dumps(response).encode(self.coding))
            recv_size = self.accept_file(file_md5_path, old_filesize, filesize)
        else:
            # 先计算一下已经上传的部分文件的md5值
            with open(file_md5_path, "rb") as f1:
                for line in f1:
                    self.file_md5.update(line)
            old_filesize = os.path.getsize(file_md5_path)
            # 1002则代表是已经存在文件,需要断点续传
            response = {'code': 1002, 'old_filesize': old_filesize}
            self.request.sendall(json.dumps(response).encode(self.coding))
            recv_size = self.accept_file(file_md5_path, old_filesize, filesize)

        shutil.move(file_md5_path, file_name_path)  # 把md5名称的文件改名为最终的filename
        file_md5_code = self.file_md5.hexdigest()  # 获取文件md5的值,字符串形式
        self.request.send(b"ok")
        recv_md5_code = self.request.recv(self.max_packet_size).decode(
            self.coding)  # 接收客户端发来的md5值
        if recv_md5_code == file_md5_code:
            print("%s文件上传成功,大小为%s字节!" % (filename, recv_size))
            self.request.send(b"1003")
        else:
            self.request.send(b"1004")

    def download(self, args):
        """实现文件下载"""
        filename = args['filename']
        file_path = os.path.normpath(os.path.join(self.user_dir, filename))
        if not os.path.exists(file_path):
            print('file:%s is not exists' % file_path)
            self.td.send_packget_dict({'code': "1009"})
            return
        else:
            print("1010")
            self.td.send_packget_dict({'code': "1010"})
        file_md5_code = self.file_md5_pro(file_path)
        filesize = os.path.getsize(file_path)  # 拿到服务器文件的md5值
        file_dict = {'filesize': filesize, 'file_md5_val': file_md5_code}
        # 发送服务端文件的大小
        self.td.send_packget_dict(file_dict)
        # 接收code,看文件是否被下载过
        file_dic = self.td.accept_packget_dict()
        exist_code = file_dic['code']
        # 接下来传输文件
        if exist_code == "1005":
            # 1005 表示客户端无该文件,全新下载
            send_size = self.send_file(0, file_path, filesize)
        else:
            old_filesize = file_dic['old_filesize']
            f_seek = old_filesize  # 文件读取的偏移量
            send_size = self.send_file(f_seek, file_path, filesize)
        # 发送文件的md5,判断文件一致性
        file_md5_client = self.request.recv(self.max_packet_size).decode(
            self.coding)
        if file_md5_client == file_md5_code:
            print("%s文件下载成功,大小为%s字节!" % (filename, send_size))
            self.request.send(b"1007")
        else:
            self.request.send(b"1008")

    def mk_dir(self, args):
        """新建文件夹"""
        filename = args['filename']
        file_path = os.path.normpath(os.path.join(self.user_dir, filename))
        if os.path.exists(file_path):
            self.td.send_packget_dict({"code": "1013"})
            print("%s目录已经存在" % filename)
            return
        else:
            self.td.send_packget_dict({"code": "1014"})
        try:
            os.mkdir(file_path)
            self.td.send_packget_dict({"code": "1015"})
            print("创建目录成功")
            return
        except:
            self.td.send_packget_dict({"code": "1015"})
            print("创建目录失败")
            return

    def checkfile(self, args):
        """查看文件夹及相关文件"""
        filename = args['filename']
        if filename == ".":
            file_path = self.user_dir
        else:
            file_path = os.path.normpath(os.path.join(self.user_dir, filename))
            print(file_path)
        if os.path.exists(file_path):
            hf = HandleFile()
            hf.get_file_tree(file_path)
            self.td.send_packget_dict({
                "code": "1013",
                "dir": os.path.basename(file_path),
                "dir_tree": hf.tree
            })
        else:
            self.td.send_packget_dict({"code": "1014"})
예제 #6
0
 def __init__(self, socket, func_str):
     self.socket = socket
     self.func_str = func_str
     self.td = TransferDic(self.socket)
예제 #7
0
class MyTcpClient:
    """登陆之后的操作"""
    MENU = [('put', '上传'), ('download', '下载'), ('mk_dir', '新建文件夹'),
            ('checkfile', '查看目录下的文件夹及文件'), ('ch_dir', '进入下一级目录'),
            ('back', '返回上一级目录'), ('logout', '退出')]

    address_family = socket.AF_INET
    socket_type = socket.SOCK_STREAM
    allow_reuse_address = False
    max_packet_size = 8192
    coding = 'utf-8'
    request_queue_size = 5

    # client_download_dir = 'file_download'

    def __init__(self, socket, func_str):
        self.socket = socket
        self.func_str = func_str
        self.td = TransferDic(self.socket)

    def client_close(self):
        self.socket.close()

    def run(self):
        # while True:
        if hasattr(self, self.func_str):
            func = getattr(self, self.func_str)
            func(self.func_str)

    def file_md5(self, file_path):
        """
        计算文件的md5值并返回
        :param file_path:文件路径
        :return:
        """
        md5 = hashlib.md5()
        with open(file_path, "rb") as f:
            for line in f:
                md5.update(line)
        return md5.hexdigest()

    def progress_bar(self, new_size, sum_size):
        """根据每次输入的大小判断目前的百分比"""
        bar = int(new_size / sum_size * 100)
        bar_num = bar // 3
        print("\r%s|进度为:%s%%" % ("#" * bar_num, bar), end="")

    def send_file(self, file_seek, filename, filesize):
        send_size = file_seek
        # 最后发送需要传输的文件
        with open(filename, 'rb') as f:
            f.seek(file_seek)
            for line in f:
                self.socket.sendall(line)
                # 后面发送的大小
                send_size += len(line)
                self.progress_bar(send_size, filesize)
            print()
        return send_size

    def accept_file(self, file_md5_path, old_filesize, filesize, file_md5):
        """接收服务端发送来的文件内容"""
        f = open(file_md5_path, "ab")
        recv_size = old_filesize  # 记录读取文件的大小
        while recv_size < filesize:
            recv_data = self.socket.recv(self.max_packet_size)
            file_md5.update(recv_data)
            f.write(recv_data)
            f.flush()  # 主动将内存数据写入硬盘
            recv_size += len(recv_data)
            self.progress_bar(recv_size, filesize)
        print()
        f.close()
        return recv_size, file_md5

    def put(self, action):
        """实现文件上传"""
        filename = input("输入需要上传的文件:")
        # 判断是否是文件
        if not os.path.isfile(filename):
            print('file:%s is not exists' % filename)
            return
        filesize = os.path.getsize(filename)
        file_md5_val = self.file_md5(filename)
        head_dic = {
            'action': action,
            'filename': os.path.basename(filename),
            'filesize': filesize,
            'file_md5': file_md5_val
        }
        # 发送文件信息的数据字典给服务器
        self.td.send_packget_dict(head_dic)
        disk_quota = self.td.accept_packget_dict()
        disk_quota_code = disk_quota['code']
        if disk_quota_code == "1011":
            print("上传的文件超过配额")
            return
        # 接收服务端发送的数据,判断是否之前已经上传或者上传过一部分
        recv_response = json.loads(
            self.socket.recv(self.max_packet_size).decode(self.coding))
        file_md5_code = self.file_md5(filename)  # 先读一遍文件获取到文件的md5的值
        if recv_response['code'] == 1001:
            # 服务器无该文件,从头开始上传
            send_size = self.send_file(0, filename, filesize)
        else:
            # 移动文件的光标到上次上传的最后接着上传
            file_seek = int(recv_response['old_filesize'])
            send_size = self.send_file(file_seek, filename, filesize)
        # 发送文件的md5,判断文件一致性
        self.socket.recv(self.max_packet_size)
        self.socket.sendall(file_md5_code.encode(self.coding))  # 发送文件的md5值给服务端
        code = self.socket.recv(self.max_packet_size).decode(self.coding)
        if code == "1003":
            print("%s字节的%s文件上传成功!" % (send_size, filename))
        else:
            print("上传失败,请重新上传!")

    def download(self, action):
        """实现文件下载"""
        filename = input("输入需要下载的文件:")
        download_dir = settings.home_path
        # file_path = os.path.normpath(os.path.join(download_dir, filename))
        head_dic = {'action': action, 'filename': os.path.basename(filename)}
        self.td.send_packget_dict(head_dic)
        file_exist_code = self.td.accept_packget_dict()['code']
        if file_exist_code == "1009":
            print('file:%s is not exists' % filename)
            return
        file_dict = self.td.accept_packget_dict()
        filesize = file_dict['filesize']
        file_md5_val = file_dict['file_md5_val']
        file_md5_path = os.path.normpath(
            os.path.join(download_dir, file_md5_val))
        file_name_path = os.path.normpath(os.path.join(download_dir, filename))
        file_md5 = hashlib.md5()  # 计算文件的md5值,保证下载的完整性
        if not os.path.exists(file_md5_path):
            # 新文件下载
            file_dic = {'code': "1005"}  # 1005则代表该文件从未下载过
            self.td.send_packget_dict(file_dic)
            old_filesize = 0
            recv_size, file_md5 = self.accept_file(file_md5_path, old_filesize,
                                                   filesize, file_md5)
        else:
            old_filesize = os.path.getsize(file_md5_path)
            # 先计算一下已经下载的部分文件的md5值
            with open(file_md5_path, "rb") as f1:
                for line in f1:
                    file_md5.update(line)
            file_dic = {
                'code': "1006",
                'old_filesize': old_filesize
            }  # 1006则代表该文件下载过
            # 发送code给服务端,表示文件已经存在
            self.td.send_packget_dict(file_dic)
            recv_size, file_md5 = self.accept_file(file_md5_path, old_filesize,
                                                   filesize, file_md5)

        shutil.move(file_md5_path, file_name_path)  # 把md5名称的文件改名为最终的filename
        file_md5_code = file_md5.hexdigest()  # 获取文件md5的值,字符串形式
        self.socket.sendall(file_md5_code.encode(self.coding))  # 发送文件的md5值给服务端
        code = self.socket.recv(self.max_packet_size).decode(self.coding)
        if code == "1007":
            print("%s字节的%s文件下载成功!" % (recv_size, filename))
        else:
            print("下载失败,请重新下载!")

    def mk_dir(self, action):
        """新建文件夹"""
        filename = input("目录名称:").strip()
        if not filename: return
        head_dic = {'action': action, 'filename': filename}
        self.td.send_packget_dict(head_dic)
        dir_exist_code = self.td.accept_packget_dict()['code']
        if dir_exist_code == "1013":
            print("目录已经存在")
            return
        dir_create_code = self.td.accept_packget_dict()['code']
        if dir_create_code == "1015":
            print("目录创建成功!")
            return
        else:
            print("目录创建失败!")
            return

    def checkfile(self, action):
        """查看文件夹及相关文件"""
        filename = input("输入查看的目录,.为当前目录:").strip()
        if not filename: return
        head_dic = {'action': action, 'filename': filename}
        self.td.send_packget_dict(head_dic)
        dir_msg = self.td.accept_packget_dict()
        dir_exist_code = dir_msg['code']
        if dir_exist_code == "1014":
            print("目录不存在")
            return
        dir_name = dir_msg['dir']
        dir_tree = dir_msg['dir_tree']
        print("当前%s目录下文件结构如下:" % (dir_name))
        print(dir_tree)
        return

    def logout(self, action):
        """退出"""
        quit("欢迎下次再来!")
예제 #8
0
 def send_accept_server(self, dic):
     """发送消息给服务端并接受返回数据"""
     td = TransferDic(self.client)
     td.send_packget_dict(dic)
     recv_dic = td.accept_packget_dict()
     return recv_dic