• python day 14: 作业:开发一个能够多用户上传文件的FTP脚本


    python day 14

    2019/10/19

    看了老师的FTP脚本之后,我下面的代码就是a piece of shit。不忍目睹。

    1. 要求

    作业

    FTP:
    1,单独功能实现(进度条,断点续传)
    2,整合
    3,bin,config,db,lib程序目录

    2. 自己写的程序目录

    自己花了5个小时写的

    3. models模块

    import os, sys
    
    sys.path.append(os.path.dirname(os.path.dirname(__file__)))
    import socketserver
    import socket
    import hashlib
    import pickle
    from config import settings
    import subprocess
    import chardet
    
    def down_file(conn):
        conn.sendall('请输入文件路径'.encode('utf-8'))
        filename = conn.recv(1024).decode('utf-8')
        print(filename)
        path = os.path.join(settings.FILE_DB_DIR, filename)
        if not os.path.exists(path):
            conn.sendall(b'1000')
            filesize = int(conn.recv(1024).decode('utf-8'))
            print(filesize)
            conn.sendall(b'ack')
            has_data = 0
            content = bytes('',encoding='ISO-8859-1')
            while has_data<filesize:
                ret = conn.recv(1024)
                # print(chardet.detect(ret))
                content += ret
                has_data += len(ret)
            f = open(path,'wb')
            f.write(content)
            f.close()
        else:
            conn.sendall(b'1001')
            exist_file_size=os.stat(path).st_size
            conn.sendall(str(exist_file_size).encode('utf-8'))
    
    
    
    
    def do_command(conn):
        conn.sendall('请输入命令'.encode('utf-8'))
        com1 = conn.recv(1024).decode('utf-8')  # ipconfig
        print(com1)
        result = subprocess.check_output(com1)
        # linux系统是以utf-8默认编码,windows是以gbk默认编码,所以此处result是以gbk编码的bytes,折腾了两个小时
        # print(result.decode('gbk'))
        conn.sendall(str(len(result)).encode('utf-8'))  # 1638
        print(conn.recv(1024))  # b'lan'
        conn.sendall('ack'.encode('utf-8'))
        print(conn.recv(1024))  # b'ack'
        result = result.decode('gb2312').encode('utf-8')
        # print(chardet.detect(result))
        conn.sendall(result)
    
    
    def login(conn, name, pwd):
        m = hashlib.md5(bytes('lan', encoding='utf-8'))
        m.update(bytes(pwd, encoding='utf-8'))
        hex1 = m.hexdigest()
        path = os.path.join(settings.CLIENT_DB_DIR, name)
        result = pickle.load(open(path, 'rb'))
        username, password = result.split('$')
        if username == name and password == hex1:
            conn.sendall('登录成功'.encode('utf-8'))
            return 1
        else:
            conn.sendall('密码错误'.encode('utf-8'))
            return 0
    
    
    def register(conn, name, pwd):
        m = hashlib.md5(bytes('lan', encoding='utf-8'))
        m.update(bytes(pwd, encoding='utf-8'))
        hex1 = m.hexdigest()
        s1 = '$'.join([name, hex1])
        print(s1)
        path = os.path.join(settings.CLIENT_DB_DIR, name)
        pickle.dump(s1, open(path, 'wb'))
        conn.sendall('用户{0}注册成功'.format(name).encode('utf-8'))
    
    
    def connect_user(conn, addr1):
        inp = '请输入用户名与密码'.encode('utf-8')
        conn.sendall(inp)
        name = conn.recv(1024).decode('utf-8')
    
        pwd = conn.recv(1024).decode('utf-8')
    
        inp2 = '1是登录;2是注册,请输入数字进行选择'.encode('utf-8')
        conn.sendall(inp2)
        ret = conn.recv(1024).decode('utf-8')
        print('来自%s的消息:
    >>>%s' % (addr1[0], ret))
        if ret == '2':
            register(conn, name, pwd)
        if ret == '1':
            result = login(conn, name, pwd)
    
            if result:
                while True:
                    inp3 = '3是执行命令;4是上传文件,请输入数字进行选择'.encode('utf-8')
                    conn.sendall(inp3)
                    ret2 = conn.recv(1024).decode('utf-8')
                    print('来自%s的消息:
    >>>%s' % (addr1[0], ret2))
                    if ret2 == '3':
                        do_command(conn)
                    elif ret2 == '4':
                        down_file(conn)
                    elif ret == 'q':
                        break
    
    
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            conn, addr2 = self.request, self.client_address
            connect_user(conn, addr2)
            # size_str = conn.recv(1024).decode('utf-8')
            # total_size_int = int(size_str)
            # print('来自%s的消息:
    >>>文件大小是%s' % (addr[0], total_size_int))
            # has_data = 0
            # file_name = conn.recv(1024).decode('utf-8')
            # print('来自%s的消息:
    >>>文件名字是%s' % (addr[0], file_name))
            # conn.sendall('ack'.encode('utf-8'))
            # f = open(file_name, 'wb')
            # while True:
            #     if has_data == total_size_int:
            #         break
            #     ret = conn.recv(1024)
            #     f.write(ret)
            #     has_data += len(ret)
            # f.close()
    
    
    # class MySocket(socket.socket):
    #     def __init__(self, family=-1, type=-1, proto=-1, fileno=None):
    #         self.name = None
    #         self.pwd = None
    #         super().__init__(family, type, proto, fileno)
    #
    #     def login(self, user, pwd):
    #         if self.name == user and self.pwd == pwd:
    #             return True
    #         else:
    #             return False
    #
    #     def register(self, user, pwd):
    #         self.name = user
    #         m = hashlib.md5()
    #         m.update(bytes(pwd, encoding='utf-8'))
    #         password = m.hexdigest()
    #         self.pwd = password
    
    
    if __name__ == '__main__':
        addr = ('192.168.131.1', 9999,)
        tcp_server = socketserver.ThreadingTCPServer(addr, MyServer)
        tcp_server.serve_forever()
    

    4. settings模块

    import os
    
    BASE_DIR = os.path.dirname(os.path.dirname(__file__))
    CLIENT_DB_DIR = os.path.join(BASE_DIR, 'db', 'client')
    FILE_DB_DIR= os.path.join(BASE_DIR, 'db', 'file')
    

    5. tcp_server模块

    import os, sys
    
    sys.path.append(os.path.dirname(os.path.dirname(__file__)))
    import pickle
    from lib.models import *
    
    
    def main():
        addr = ('192.168.131.1', 9999,)
        tcp_server = socketserver.ThreadingTCPServer(addr, MyServer)
        tcp_server.serve_forever()
    
    
    if __name__ == '__main__':
        main()
    

    6. client模块

    import os, sys
    import socket
    
    sys.path.append(os.path.dirname(os.path.dirname(__file__)))
    from lib.models import *
    import hashlib
    import getpass
    import chardet
    import pickle
    
    
    def recv_com(obj):
        file_size = int(obj.recv(1024).decode('utf-8'))
        print(file_size)  # 1857
        has_data = 0
        obj.sendall('lan'.encode('utf-8'))
        print(obj.recv(1024))  # b'ack
        obj.sendall(b'ack')
        ret3 = ''
        while has_data < file_size:
            data = obj.recv(1024)
            # print(chardet.detect(data))
            ret3 += data.decode('utf-8')
            has_data += len(data)
            # has_data = len(obj.recv(1024)) 这里还会再执行一次接收数据动作,所以就是这里卡住了。
    
        print(ret3)
    
    
    def load_file(obj):
        command1 = obj.recv(1024).decode('utf-8')  # 文件路径
        print(command1)
        file_path = input('文件路径是:
    >>>').strip()
        file_name = os.path.split(file_path)[1]
        obj.sendall(file_name.encode('utf-8'))
    
        ret_code = obj.recv(1024)
        if ret_code ==b'1000':
            file_size = os.stat(file_path).st_size  # int类型
            obj.sendall(str(file_size).encode('utf-8'))
            obj.recv(1024)
            with open(file_path, 'rb') as f:
                for i in range(1,file_size+1):
                    file_content = f.read(1)
                    obj.sendall(file_content)
                    sys.stdout.write('
    ')
                    sys.stdout.write('%.2f%% |%s' % (i / file_size * 100, int(i / file_size * 100) * '#'))
                    sys.stdout.flush()
        elif ret_code==b'1001':
            pass
    
    def connect_server():
        obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        addr = ('192.168.131.1', 9999,)
        obj.connect(addr)
        ret_str = obj.recv(1024).decode('utf-8')
        print('来自%s的消息:
    >>>%s' % (addr[0], ret_str))
        user = input('请输入用户名:>>>').strip()
        obj.sendall(user.encode('utf-8'))
        pwd = getpass.win_getpass('password:')
        obj.sendall(pwd.encode('utf-8'))
    
        result2 = str(obj.recv(1024), encoding='utf-8')  # 1是登录;2是注册,请输入数字进行选择
        print('来自%s的消息:
    >>>%s' % (addr[0], result2,))
        inp = input('请输入发送给%s的消息:
    >>>' % addr[0]).strip()  # 1
        obj.sendall(inp.encode('utf-8'))
    
        result2 = str(obj.recv(1024), encoding='utf-8')
        print('来自%s的消息:
    >>>%s' % (addr[0], result2,))  # 登录成功
    
        while True:
            result2 = str(obj.recv(1024), encoding='utf-8')
            print('来自%s的消息:
    >>>%s' % (addr[0], result2,))
            # 3是执行命令;4是上传文件,请输入数字进行选择
            inp = input('请输入发送给%s的消息:
    >>>' % addr[0]).strip()
            obj.sendall(inp.encode('utf-8'))  # 3
            if inp == '3':
                result2 = str(obj.recv(1024), encoding='utf-8')
                print('来自%s的消息:
    >>>%s' % (addr[0], result2,))  # 请输入命令
                inp = input('请输入发送给%s的消息:
    >>>' % addr[0]).strip()
                obj.sendall(inp.encode('utf-8'))  # ipconfig
                recv_com(obj)
            elif inp == '4':
                load_file(obj)
            elif inp == 'q':
                obj.close()
                break
    
    
    def main():
        '''
        客户端主程序
        :return:
        '''
        connect_server()
        # ret = obj.recv(1024).decode('utf-8')
        # print('来自%s的消息:
    >>>%s' % (addr[0], ret))
        # inp = input('请输入要传送的文件路径:
    >>>').strip()
        # size = str(os.stat(inp).st_size, encoding='utf-8')
        # file_name = os.path.split(inp)[1]
        # obj.sendall(size.encode('utf-8'))
        # obj.sendall(file_name.encode('utf-8'))
        # obj.recv(1024)
        # with open(inp, 'rb') as f:
        #     for line in f:
        #         if line:
        #             obj.sendall(line)
        #         else:
        #             print('传送完毕')
        #             break
        # obj.close()
    
    
    if __name__ == '__main__':
        main()
    

    7. 后记

    只实现了多用户md5登录,命令执行,文件传递,进度条显示,并没有实现文件续传功能。
    还需要修改。不过也折腾了近5个小时,在编码的转换问题上折腾了好久。
    下次一定要记住使用chardet模块的detect方法先检测下编码,然后按照对应的编码方式进行编码与解码。

  • 相关阅读:
    paip.数据库全文检索 attilax总结
    软件网站安全性的设计与检测与解决方案
    防止SQL注入解决方案
    paip.账务系统的安全性
    快速开发字段很多的MIS表
    paip.php调试不能显示局部变量内容w/ xdebug
    程序安全性之配置文件安全
    paip.VS2010未能加载类型
    paip.盘古汉字转拼音组件库使用总结
    paip.跟踪DISCUZ积分日志功能总结
  • 原文地址:https://www.cnblogs.com/lanxing0422/p/pythonday14.html
Copyright © 2020-2023  润新知