zoukankan      html  css  js  c++  java
  • 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",
    "status":0,
    "type":0,
    "home":"home\alex",
    "disk_quota":0.97
    }
    student_view
     
     
     
  • 相关阅读:
    python爬虫之趟雷
    python附录-builtins.py模块str类源码(含str官方文档链接)
    python-基础学习篇(一)
    pycharm和webstorm永久激活方法
    计算机网络基础概述
    计算机基础
    B/S和C/S架构简单理解
    认识HTML中文本、图片、链接标签和路径
    结对开发
    全国疫情可视化地图 (一)
  • 原文地址:https://www.cnblogs.com/gaodi2345/p/11412810.html
Copyright © 2011-2022 走看看