zoukankan      html  css  js  c++  java
  • 老男孩Day8作业:FTP

    1、作业需求

    开发简单的FTP:

    1. 用户登陆

    2. 上传/下载文件

    3. 不同用户家目录不同

    4. 查看当前目录下文件

    5. 充分使用面向对象知识

    2、流程图

    3、目录结构

     

    4、代码区

    bin目录下的start.py程序执行文件

    # -*- coding:utf-8 -*-
    # Author:D.Gray
    import os,sys
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    
    from core import ftp_client
    fc = ftp_client.FTP_client()
    start_client.py
    # -*- coding:utf-8 -*-
    # Author:D.Gray
    import os,sys
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    from core import ftp_server
    fs = ftp_server.FTP_server()
    start_server.py

    conf目下的setting.py系统配置文件

    # -*- coding:utf-8 -*-
    # Author:D.Gray
    import os,sys,socket
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    #IP地址和端口
    IP_PORT = ("localhost",6969)
    
    #数据文件路径
    USER_FILE = BASE_DIR + r"dbuser.db"
    
    #用户文件目录
    USER_HOME = BASE_DIR
    setting.py

    core目录下主程序文件

    # -*- coding:utf-8 -*-
    # Author:D.Gray
    import os,sys,socket
    from conf import setting
    from core import ftp_server
    from core import users
    class FTP_client(object):
        def __init__(self):
            self.client = setting.socket.socket()
            self.client.connect(setting.IP_PORT)
            self.user_obj = users.Users()
            self.help_info = {
                "get":"用于上传文件,例如:get readme.txt 即 get 文件名",
                "put":"用于下载文件,例如:put readme.txt 即 put 文件名",
                'dir':"用于显示当前目录下文件或文件详细信息 格式 ls "
            }
            if self.auth():
                self.start()
    
        def auth(self):
            '''
            用户登录验证函数
            :return:
            '''
            while True:
                username = input("请输入用户名>>>:").strip()
                pwd = input("请输入用户密码>>>:").strip()
                auth_info = 'auth %s %s'%(username,pwd)  #格式化输出 auth 用户名 密码
                self.client.send(auth_info.encode())    #将格式化后的内容发送给服务端
                back_res = self.client.recv(1024).decode()
                if back_res == "ok":
                    print('认证成功')
                    user = self.user_obj.get_user(username)
                    self.current_user = username
                    self.current_pwd = pwd
                    self.current_path = user['home']
                    self.current_dir = back_res[1]
                    return  True
                elif back_res == "Not password":
                    print("33[31;1m密码不正确33[0m")
                else:
                    print("33[31;1m用户不存在33[0m")
    
        def start(self):
            '''
            输入指令上传下载文件函数
            :return:
            '''
            while True:
                user_input = input('%s>>>:'%self.current_user).strip()
                if len(user_input) == 0:continue
                user_input = user_input.split()
                if user_input[0] == 'q':break
                if hasattr(self,user_input[0]):
                    func = getattr(self,user_input[0])
                    func(user_input)
                else:
                    print("33[31;1m请输入有效指令33[0m")
                    continue
    
        def put(self,cmd):
            '''
            从服务器端下载文件函数
            :param cmd:
            :return:
            '''
            print('in the put:',cmd)
            send_server_info = '%s %s'%(cmd[0],cmd[1])  #格式化输出['方法','文件名']
            self.client.send(send_server_info.encode()) #将格式化输出内容发送给服务器端
            server_back = self.client.recv(1024).decode()   #接收服务器回调结果
            print("接收服务器回调信息:",server_back)
            if server_back == "302":
                print('33[31;1m文件不存在33[0m')
            else:
                file_totle_size = int(server_back)  #从服务器端接收文件大小
                print("您要下载的文件大小为:%sByte"%file_totle_size)
                self.client.send('可以开始下载了...'.encode())
                rever_file_size = 0 #接收到的文件大小
                file_name_path = setting.USER_HOME + self.current_path + '\user_home\' + cmd[1]
                #print(file_name_path)
                with open(file_name_path,"wb") as f:
                    while rever_file_size < file_totle_size:
                        if file_totle_size - rever_file_size < 1024:  #当剩余文件大小<1024 全部接收文件
                            size = file_totle_size - rever_file_size
                        else:
                            size = 1024
                        data = self.client.recv(size)   #当剩余文件<1024全部接收文件,当剩余文件>1024每次只接收1024
                        rever_file_size += len(data)    #每次接收数据时自动累计rever_file_size值
                        print("已接收%sByte"%rever_file_size)
                        f.write(data)
                    else:
                        print('接受完毕')
    
        def get(self,cmd):
            '''
            本地上次文件给服务器端
            :param cmd: 接收用户通过start函数输入的操作指令
            :return:
            '''
            print(cmd)
            file_path = setting.USER_HOME + self.current_path +'\user_home\' + cmd[1]
            if os.path.isfile(file_path):
                file_totle_size = os.stat(file_path).st_size
                print('您要上传文件大小为【%sByte】'%file_totle_size)
                file_info = '%s %s %s'%(cmd[0],cmd[1],file_totle_size) #格式化输出['操作指令','文件名','文件大小']
                self.client.send(file_info.encode())    #将格式化输出内容发送给服务器端
                server_back = self.client.recv(1024).decode()   #接收回调信息
                if server_back == "300":
                    print('可以上传文件了...')
                    send_file_size = 0
                    with open(file_path,'rb') as f:
                        while send_file_size != file_totle_size:
                            if file_totle_size-send_file_size <= 1024:
                                data = f.read(file_totle_size-send_file_size)
                                send_file_size += file_totle_size - send_file_size
                            else:
                                data = f.read(1024)
                                send_file_size += len(data)
                            print("已上传【%sByte】"%send_file_size)
                            self.client.send(data)
                        print("上传成功")
            else:
                print('33[31;1m文件不存在33[0m')
    
        def dir(self,cmd):
            '''
            查看服务端目录文件信息
            :param cmd:
            :return:
            '''
            print(cmd)
            send_server_info = '%s'%cmd[0]  #格式化输出用户指令
            self.client.send(send_server_info.encode())
            server_back = self.client.recv(1024).decode()   #接收服务端回调
            print("获取服务端回调信息:%s"%server_back)
            self.client.send("ok".encode())   #发送给服务端'ok'
            recv_size = 0
            recv_data = b''
            while recv_size < int(server_back):
                data = self.client.recv(1024)
                recv_data += data
                recv_size = len(data)
                print(recv_size)
            else:
                print(recv_data.decode())
    
    
        def help(self,cmd):
            '''
            查看帮助文档函数
            :param cmd:
            :return:
            '''
            print(cmd)
            d = self.help_info
            print(d)
    ftp_client.py
    # -*- coding:utf-8 -*-
    # Author:D.Gray
    import os,sys,socket
    from conf import setting
    from core import ftp_client
    from core import users
    
    class FTP_server(object):
        def __init__(self):
            self.server = setting.socket.socket()
            self.server.bind(setting.IP_PORT)
            self.server.listen(5)
            self.user_obj = users.Users()  #导入users文件并实例化Users类
            self.start()
    
        def start(self):
            print("等待链接中...")
            while True:
                self.conn,self.addr = self.server.accept()
                print("一个新的链接:%s %s"%(self.conn,self.addr))
                while True:
                    self.data = self.conn.recv(1024)  #接受客户端格式化输出内容
                    #print('data:',self.conn)
                    if not self.data:
                        print("客户端断开")
                        break
                    cmd_res = self.data.decode().split() #以列表形式获取用户输入的[[方法名],[文件名]]
                    cmd_action = cmd_res[0]     #获取方法名
                    #print('in the start获取方法名:',cmd_action)
                    if hasattr(self,cmd_action):    #判断用户输入的方法名是否存在
                        func = getattr(self,cmd_action) #执行对应的方法函数
                        func(cmd_res)   #用户输入的[[方法名],[文件名]]传给方法函数
                    else:
                        print("33[31;1m请输入有效命令33[0m")
    
        def auth(self,cmd):
            #print('auth:',cmd) #接受客户端格式化输出的 auth 用户名 密码
            user = self.user_obj.get_user(cmd[1])   #调用Users类中get_user方法,并把cmd[1](用户名)传参给get_user方法
            print('in the ftp_server_auth:',user)
            if user:
                if user['password'] == cmd[2]:
                    self.current_user = user
                    self.current_path = user["home"]
                    self.user_home = setting.USER_HOME
                    self.conn.send(b"ok")
                else:
                    self.conn.send(b"Not password")
            else:
                self.conn.send(b'Not username')
    
        def put(self,cmd):
            '''
            上传文件函数
            :param cmd: 接收用户输入的[[方法名],[文件名]]
            :return:
            '''
            #print('in the put:',cmd)
            file_name_path = self.user_home + self.current_path +'server_home\'+ cmd[1]
            print('文件路径',file_name_path)
            if os.path.isfile(file_name_path):
                file_totle_size = os.stat(file_name_path).st_size #查看文件大小
                self.conn.send(str(file_totle_size).encode())   #将文件大小发送给客户端
                self.conn.recv(1024)    #接收客户端消息
                with open(file_name_path,'rb') as f:
                    for line in f:      #循环遍历文件内容
                        self.conn.send(line)    #并将文件内容发送给客户端
                print("send done>>>")
            else:
                print('33[31;1m文件不存在33[0m')
                self.conn.send('302'.encode())
    
        def get(self,cmd):
            '''
            接收客户端上传文件函数
            :param cmd:
            :return:
            '''
            print(cmd)
            file_path = self.user_home + self.current_path + 'server_home\' + cmd[1]  #文件路径
            file_totle_size = cmd[2]    #接收客户端上传文件大小
            file_totle_size = int(file_totle_size)
            with open(file_path,'wb') as f:
                self.conn.send('300'.encode())  #返回客户端参数300
                revered_file_size = 0   #初始接收文件大小
                while revered_file_size < file_totle_size:  #开始接收客户端上传文件
                    if file_totle_size - revered_file_size <= 1024:
                        size = file_totle_size-revered_file_size
                    else:
                        size = 1024
                    data = self.conn.recv(size)
                    revered_file_size += len(data)
                    f.write(data)
                else:
                    print("文件接收完毕")
    
        def dir(self,cmd):
            '''
            查看服务端目录文件信息函数
            :param cmd:
            :return:
            '''
            print(cmd)
            file_path = self.user_home + self.current_path + 'server_home\'
            res = os.popen('%s %s'%(cmd[0],file_path)).read()
            print('服务端文件目录信息:',res)
            if len(res) == 0 :
                res = 'cmd has not output'
            self.conn.send(str(len(res)).encode()) #服务端发送目录文件大小给客户端
            self.conn.recv(1024)    #接收客户端回调信息 "ok"
            self.conn.send(res.encode()) #服务端发送目录文件信息给客户端
    ftp_server.py
    #-*- Coding:utf-8 -*-
    # Author: D.Gray
    import os,sys,shelve
    
    from conf import setting
    class Users(object):
    
    
        def __init__(self):
            self.user_file = setting.USER_FILE
            self.users_read = self.read_users()
    
        def read_users(self):
            print(self.user_file)
            with open(self.user_file, 'r') as f:
                user_read = eval(f.read())
            return user_read
    
        def get_users(self):
            print(self.users_read)
            return self.users_read
    
        def get_user(self,username):
            for user in self.users_read:
                print('in the User_get_user:',user)
                if user["username"] == username:
                    return user
    users

    db目录下的数据文件

    [
        {
            "username":"alex",
            "password":"admin",
            "home":"\home\alex\",
        }
    ]
    user.db
  • 相关阅读:
    python三元表达式
    购物车的升级系统
    python迭代器
    python函数装饰器
    python 闭包函数
    python名称空间与作用域
    python函数的嵌套
    python函数对象
    python函数之可变长参数
    python函数的参数
  • 原文地址:https://www.cnblogs.com/catepython/p/8483617.html
Copyright © 2011-2022 走看看