zoukankan      html  css  js  c++  java
  • Python学习第42天(ftp习题实现day4)

    今天为止,大多数的功能已经得到实现了,目前还缺三个部分内容,一个是账号注册问题(缺少configpraser模块知识,得抓紧看),二是上传和下载后文件一致性验证的问题,三是用户存储文件大小的限制。  

    但是目前已经可以基本实现一个网盘的功能,所有部分的代码如下:

    bin文件:

    ftp_server.py

    import os,sys
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    from core import main
    
    if __name__ == '__main__':
        main.ArgvHandler()
    #提供程序入口

    mian.py

    import socketserver
    import optparse
    
    from conf import settings
    from core import server
    
    
    class ArgvHandler():
    
        def __init__(self):
            self.op = optparse.OptionParser()
            # self.op.add_option('-s','--server',dest = 'server')
            # self.op.add_option('-p','--p',dest = 'port')
            # 解析模块,暂时未使用到,是argv输入进来的参数以键值对形式保存,打印出来像字典,但是不是字典,通过.的方式调用
            options,args = self.op.parse_args()
    
            # 假设在运行的初期输入的参数为 -s 127.0.0.1 -p 8080
            # print(options)   # {'server' : '127.0.0.1' , 'port' : 8080}
            # print(type(options))   # options 的数据类型是optparse的实例对象
            # print(args)        # 用于接收后面那些没有标识符作为前缀的参数
    
            self.verify_args(options,args)
    
        def verify_args(self,options ,args):
    
            cmd = args[0]
            if hasattr(self,cmd):
                func = getattr(self,cmd)
                func()
    
        def start(self):
            print('==========welcome ftp_server==========')
            s = socketserver.ThreadingTCPServer((settings.IP , settings.PORT),server.ServerHandler)
            s.serve_forever()
            print('.....')

    server.py

    import socketserver
    import json
    import configparser
    from conf import settings
    import os,sys
    
    STATUS_CODE  = {
        250 : "Invalid cmd format, e.g: {'action':'get','filename':'test.py','size':344}",
        251 : "Invalid cmd ",
        252 : "Invalid auth data",
        253 : "Wrong username or password",
        254 : "Passed authentication",
        255 : "Filename doesn't provided",
        256 : "File doesn't exist on server",
        257 : "ready to send file",
        258 : "md5 verification",
    
        800 : "the file exist,but not enough ,is continue? ",
        801 : "the file exist !",
        802 : " ready to receive datas",
    
        900 : "md5 valdate success"
    
    }
    
    class ServerHandler(socketserver.BaseRequestHandler):
    
        def handle(self):
            while True:
                data = self.request.recv(1024).strip()
                data = json.loads(data.decode('utf-8'))
                '''
                {'action' : 'auth' ,
                 'username' : 'xiao',
                 'password' : 123 }
                '''
            if data.get('action'):
    
                if hasattr(self,data.get('action')):
                    func = getattr(self,data.get('action'))
                    func(**data)
                else:
                    print('func error')
                    self.request.send('func error'.encode('utf-8'))
            else:
                print('Invalid cmd')
                self.request.send('Invalid cmd'.encode('utf-8'))
    
        def send_reponse(self , state_code):
            response = {'status_code':state_code}
            self.request.sendall((json.dumps(response)).encode('utf-8'))
    
        def auth(self,**data):
            username = data['username']
            password = data['password']
    
            user = self.authenticate(username,password)
    
            if user:
                self.send_reponse(254)
            else:
                self.send_reponse(253)
    
    
        def authenticate(self,user,pwd):
            cfg = configparser.ConfigParser()
            cfg.read(settings.ACCOUNT_PATH)
    
            if user in cfg.sections():
                if cfg[user]['password'] == pwd:
                    self.user = user  # 登录成功之后保存了用户的登录信息
                    self.mainPath = os.path.join(settings.BASE_DIR,'home',self.user)
                    # print('passed authentication')  # 表示登录成功
    
                    return user
    
        def put(self,**data):
            print('data',data)
            file_name = data.get('file_name')
            file_size = data.get('file_size')
            target_path = data.get('target_path')
    
            abs_path = os.path.join(self.mainPath,target_path,file_name)
            # 以上部分即已获得了想要保存文件在服务端的位置信息,可用于后续文件的打开
    
            has_received = 0
            if os.path.exists(abs_path):
            # 用于判断文件是否已经存在
                file_has_size = os.stat(abs_path).st_size
                if file_has_size < file_size:
                    # 出现了断点续传的情况
                    self.request.sendall('800'.encode('utf-8'))
                    choice = self.request.recv(1024).decode('utf-8')
                    if choice == 'Y':
                        self.request.sendall(str(file_has_size).encode('utf-8'))
                        has_received += file_has_size
                        f = open(abs_path,'ab')
    
                    else:
                        f = open(abs_path,'wb')
    
                    # 继续完善部分
                else:
                    # 表示文件已存在,且比较完整,返回给客户端801的信息
                    self.request.sendall('801'.encode('utf-8'))
                    return
            else:
                self.request.sendall('802'.encode('utf-8'))
                f = open(abs_path , 'wb')
    
            while has_received < file_size:
                try:
                    data = self.request.recv(1024)
                except Exception as e:
                    break
                f.write(data)
                has_received += len(data)
            f.close()
    
        def ls(self,**data):
            #相当于dos命中的dir,显示当前文件目录下的所有文件
            file_list = os.listdir(self.mainPath)
    
            file_str = "
    ".join(file_list)
            # file_list 是一个列表的形式,通过.join方法让其自动的实现换行显示
            if not len(file_list):
                # 表示如果该文件目录为空的情况
                file_str = "<empty dir>"
            self.request.sendall(file_str.encode("utf8"))
    
        def cd(self,**data):
    
            dirname=data.get("dirname")
    
            if dirname=="..":
                self.mainPath=os.path.dirname(self.mainPath)
            else:
    
                 self.mainPath=os.path.join(self.mainPath,dirname)
    
            self.request.sendall(self.mainPath.encode("utf8"))
    
        def mkdir(self,**data):
    
            dirname=data.get("dirname")
    
            path=os.path.join(self.mainPath,dirname)
    
            if not os.path.exists(path):
                if "/" in dirname:
                    os.makedirs(path)
                else:
                    os.mkdir(path)
                self.request.sendall("create success".encode("utf8"))
            else:
                self.request.sendall("dirname exist".encode("utf8"))

    以上是服务端的主要内容,客户端部分信息明显要少很多

    import socket
    import optparse
    import configparser
    import json
    import os
    import sys
    
    STATUS_CODE  = {
        250 : "Invalid cmd format, e.g: {'action':'get','filename':'test.py','size':344}",
        251 : "Invalid cmd ",
        252 : "Invalid auth data",
        253 : "Wrong username or password",
        254 : "Passed authentication",
        255 : "Filename doesn't provided",
        256 : "File doesn't exist on server",
        257 : "ready to send file",
        258 : "md5 verification",
    
        800 : "the file exist,but not enough ,is continue? ",
        801 : "the file exist !",
        802 : " ready to receive datas",
    
        900 : "md5 valdate success"
    
    }
    # tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # tcp_client.connect(('127.0.0.1',8080))
    # tcp_client.send('ok'.encode('utf-8'))
    # 以上是easy模式下的
    
    class ClientHandler():
        def __init__(self):
            self.op = optparse.OptionParser()
    
            self.op.add_option('-s','--server', dest = 'server')
            self.op.add_option('-P', '--port', dest='port')
            self.op.add_option('-u', '--username', dest='username')
            self.op.add_option('-p', '--password', dest='password')
    
            self.options,self.args = self.op.parse_args()
    
            self.verify_args(self.options,self.args)
    
            self.make_connection()
    
            self.mainPath = os.path.dirname(os.path.abspath(__file__))
    
            self.last = 0
    
        def verify_args(self,options,args ):
            # 对port端口进行校验
            server = options.server
            port = options.port
            # username = options.username
            # password = options.password
    
            if int(options.port) > 0 and int(port) < 65535:
                return True
            else:
                exit('the port is in 0~65535')
    
        def make_connection(self):
            self.sock = socket.socket()
            self.sock.connect((self.options.server, int(self.options.port)))
            print('已连接')
    
        def interractive(self):
            if self.authenticate():
                print('==========begin to interactive==========')
                cmd_info = input('[%s]'%self.user).strip()   #比如会输入 put 12.png images
    
                cmd_list = cmd_info.split('')
                if hasattr(self.cmd_list[0]):
                    func = getattr(self,cmd_list[0])
                    func(*cmd_list)
    
        def put(self, *cmd_list):
            # 传入命令: put 12.png images
            action, local_path, target_path = cmd_list
            local_path = os.path.join(self.mainPath , local_path)
    
            file_name = os.path.basename(local_path)
            file_size = os.stat(local_path).st_size
    
            data = {
                'action' : 'put',
                'file_name' : file_name,
                'file_size' : file_size,
                'target_path' : target_path
            }
    
            self.sock.sendall(json.dumps(data).encode('utf-8'))
            is_exist = self.sock.recv(1024).decode('utf-8')
    
            # 下面对接收到的信息进行处理(转入服务端的书写)
            has_sent = 0
            if is_exist == '800':
                # 表示文件存在不完整,即断点续传问题
                choice = input('文件已存在,但文件不完整(Y继续上传/N重新上传>>>').strip()
                if choice.upper() == 'Y':
                    self.sock.sendall('Y'.encode('utf-8'))
                    continue_position = self.sock.recv(1024).decode('utf-8')
                    has_sent += int(continue_position)
    
                else:
                    self.sock.sendall('N'.encode('utf-8'))
    
            elif is_exist == '801':
                # 表示文件已经存在,不用上传,所以就跳出put方法,重新转入输入命令那一行
                # 即 interractive 方法
                print("the file exist")
                return
            else:
                pass
    
            # 下面表示文件不存在的情况,就直接开始上传了
            f = open(local_path, "rb")
            f.seek(has_sent)
    
            while has_sent < file_size:
                data = f.read(1024)
                self.sock.sendall(data)
                has_sent += len(data)
                self.show_progress(has_sent, file_size)
    
            f.close()
    
            print("put success!")
    
        def show_progress(self,has,total):
            rate = float(has)/float(total)
            rate_num = int(100*rate)
            # if self.last != rate_num
            sys.stdout.write("%s%% %s
    "%(rate_num,"-"*rate_num))
    
    
        def authenticate(self):
            if self.options.username is None or self.options.password is None:
                username = input('username>>>')
                password = input('password>>>')
                print('ok')
                return self.get_auth_result(username,password)
            else:
                return self.get_auth_reult(self.options.username,self.options.password)
    
        def response(self):
            data = self.sock.recv(1024).decode('utf-8')
            data = json.loads(data)
            return data
    
        def get_auth_result(self,user ,pwd):
            data = {
                'action' : 'auth',
                'username' : user,
                'password' : pwd
            }
    
            self.sock.sendall((json.dumps(data)).encode('utf-8'))
            response = self.response()
            print('response是',response['status_code'])
    
            if response['status_code'] == 254:
                self.user = user
                self.current_dir =user
                print(STATUS_CODE[254])
                return True
            else:
                print(STATUS_CODE['status_code'])
    
        def ls(self,*cmd_list):
            # 相当于dos命中的dir,显示当前文件目录下的所有文件
            data = {
                'action' : 'ls'
            }
    
            self.sock.sendall(json.dumps(data).encode('utf-8'))
            data = self.sock.recv(1024).decode('utf-8')
            print(data)
    
        def cd(self,*cmd_list):
            data = {
                "action": "cd",
                "dirname": cmd_list[1]
            }
            self.sock.sendall(json.dumps(data).encode("utf8"))
    
            data = self.sock.recv(1024).decode("utf8")
            print(os.path.basename(data))
            self.current_dir = os.path.basename(data)
    
    
    ch = ClientHandler()
    
    ch.interractive()

    其实里面有很多的重复代码可以进行提炼,这个初级版本也是一边看视频一边写出来的,有很多不完善的地方,亟需改进

    下一步,自己晾个一两天,然后自己试一试根据自己的分析进行编写,如果还是弄不出来,就得好好抄写几遍了。

  • 相关阅读:
    继续学习AJAX
    最近在看AJAX
    selenium学习模拟键盘按键操作
    二十三。克隆
    二十五。继承
    十八。类的属性
    二十一。第四章综合例题
    二十四。继承
    十七。对JAVA中堆和栈的细致了解
    十六。方法调用以及传参
  • 原文地址:https://www.cnblogs.com/xiaoyaotx/p/12635446.html
Copyright © 2011-2022 走看看