python之路——作业:Select FTP(仅供参考)

一、作业需要

使用SELECT或SELECTORS模块实现并发简单版FTP
允许多用户并发上传下载文件

二、README

程序实现了以下功能:
    1、用户登录注册(测试用户:japhi、alex;密码都是123)
    2、上传/下载文件(已有示例文件)
    3、查看不同用户自己家得目录下文件
    4、使用了selector模块,实现单线程下并发效果

客户端启动程序:Client_start.py
服务端启动程序:Server_start.py

三、目录说明

Select FTP/
|-- Select FTPClient/              #客户端文件夹
|   |-- 示例文件夹/         #客户端上传/下载示例文件夹
|   |-- Client_start.py     #客户端启动程序
|
|-- FTPServer/              #服务端文件夹
|   |-- bin/
|   |   |-- __init__.py
|   |   |-- Server_start.py   #程序启动的主入口
|   |
|   |-- conf/
|   |   |-- setting.py         #配置文件
|   |
|   |-- db/                    #用户数据
|   |   |-- alex               #用户名alex的数据文件夹
|   |   |-- japhi              #用户名japhi的数据文件夹
|   |
|   |-- home/
|   |   |-- alex/               #用户alex用户家目录
|   |   |-- japhi/              #用户japhi用户家目录
|   |
|-- log/
|   |-- log_sys.log             #日志文件
|
|-- src/
|   |-- __init__.py
|   |-- common.py               #公共函数功能
|   |-- main.py                 #程序主函数
|   |-- user.py                 #用户类及方法
|
|-- FTP.png                     #流程图
|-- README.txt

四、流程图

五、代码说明

1、Select FTPClient/Client_start.py

import socket,os,sys,time
Basedir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),"FTPServer")
updir = os.path.join(os.path.dirname(os.path.abspath(__file__)),"示例文件夹")
sys.path.append(Basedir)
HOST = "localhost"
PORT = 6960

def upload(client,user_info,name):
    ‘‘‘
    客户端上传文件的函数
    :param client:scoket客户端标志
    :param user_info:客户端登陆用户的信息
    :param name:客户端登陆用户的名字
    :return:none
    ‘‘‘
    print("\033[1;37m当前可选上传\033[0m".center(40,"*"))
    dic = {}
    for root, dirs, files in os.walk(updir):
        for i,j in enumerate(files):
            k = i+1
            dic[k] = j
            print("\033[1;37m%s:%s\033[0m"%(k,j))
    choice = input("请输入要上传的文件序号:>>>")
    command = "upload+"+user_info
    client.send(bytes(command,encoding="utf-8"))
    res = client.recv(1024)
    if str(res,encoding="utf-8") == "True":
        dir = os.path.join(updir,dic[int(choice)])
        f = open(dir,"rb")
        data = f.read()
        length = str(len(data))
        command2 = "uploadfile+"+user_info+"+"+length+"+"+dic[int(choice)]
        client.send(command2.encode("utf-8"))
        client.recv(1024)
        # time.sleep(0.5)
        client.sendall(data)
        time.sleep(1)
        print("\033[1;37m文件上传成功\033[0m")
        f.close()

def download(client,user_info,name):
    ‘‘‘
    客户端下载文件的函数
    :param client: scoket客户端标志
    :param user_info: 客户端登陆的用户信息
    :param name:客户端登陆的用户名字
    :return: none
    ‘‘‘
    dic = {}
    command = "download+"+user_info
    client.sendall(bytes(command, encoding="utf-8"))
    data = client.recv(4069)
    res = eval(str(data, encoding="utf-8"))
    if len(res) == 0:
        print("\033[1;31m当前目录下暂无文件\033[0m".center(40, "-"))
    else:
        for i,j in enumerate(res):
            k = i + 1
            dic[k] = j
            print("\033[1;37m%s:%s\033[0m" % (k, j))
        choice = input("请选择要下载的文件序号:>>>")
        command2 = "downloadfile+"+user_info+"+"+dic[int(choice)]
        client.send(bytes(command2 , encoding="utf-8"))
        print("\033[1;37m准备开始下载文件\033[0m")
        dir = os.path.join(updir, dic[int(choice)])
        res_length = str(client.recv(1024).decode())
        # client.send("True".encode("utf-8"))         #防止方式黏包
        length = 0
        f = open(dir, "wb")
        while length < int(res_length):
            if int(res_length) - length > 1024:
                size = 1024
            else:
                size = int(res_length) - length
            data = client.recv(size)
            length += len(data)
            f.write(data)
        if length == int(res_length):
            time.sleep(1)
            print("\033[1;37m文件下载成功\033[0m")
            f.close()

def view_file(client,user_info,name):
    ‘‘‘
    客户端查看当前目录下文件的函数
    :param client: scoket客户端标志
    :param user_info: 客户端登陆的用户信息
    :param name: 客户端登陆的用户名字
    :return: none
    ‘‘‘
    command = "view+"+user_info
    client.sendall(bytes(command,encoding="utf-8"))
    data = client.recv(1024)
    res = eval(str(data,encoding="utf-8"))
    if len(res) == 0:
        print("\033[1;31m当前目录下暂无文件\033[0m".center(40, "-"))
    else:
        for i in res:
            print("\033[1;35m%s\033[0m"%i)

def operate(client,user_info,name):
    ‘‘‘
    客户端操作主函数
    :param client: scoket客户端标志
    :param user_info: 客户端登陆的用户信息
    :param name: 客户端登陆的用户名字
    :return: none
    ‘‘‘
    dic = {"1":upload,"2":download,"3":view_file}
    info = ‘‘‘------操作指令------
    1、上传文件
    2、下载文件
    3、查看目录下文件
    4、退出
    ‘‘‘
    while True:
        print("\033[1;33m%s\033[0m" % info)
        choice = input("请输入你要操作的命令:>>>").strip()
        if choice.isdigit() and 0 < int(choice) <= len(dic):
            dic.get(choice)(client,user_info,name)
        elif choice.isdigit() and int(choice) == 4:
            break
        else:
            print("\033[1;31m输出错误\033[0m".center(40, "-"))

def com_parse(client,com):
    ‘‘‘
    客户端用户登陆注册命中解析函数
    :param client: 客户端scoket标志
    :param com: 命令
    :return: 登陆成功返回True,否则False
    ‘‘‘
    client.sendall(com.encode("utf-8"))
    re = client.recv(4096)
    if str(re,encoding="utf-8") == "Success":
        return True
    elif str(re, encoding="utf-8") == "Success":
        return False

def login(client,data):
    ‘‘‘
    客户端用户登陆函数
    :param client: 客户端scoket标志
    :param data: 数据
    :return: none
    ‘‘‘
    name = input("请输入您的名字:>>>").strip()
    psd = input("请输入密码:>>>").strip()
    user_info = name+"+"+psd
    com = "login+"+user_info
    if com_parse(client,com):
        print("\033[1;31m登陆成功\033[0m")
        operate(client,user_info,name)
    else:
        print("\033[1;31m登陆出现异常\033[0m")

def register(client,data):
    ‘‘‘
    客户端用户注册函数
    :param client: 客户端scoket标志
    :param data: 数据
    :return: none
    ‘‘‘
    name = input("请输入您的名字:>>>").strip()
    psd = input("请输入密码:>>>").strip()
    com = "register+" + name + "+" + psd
    if com_parse(client, com):
        user_info = name + "+" + psd
        print("\033[1;31m注册成功\033[0m")
        operate(client, user_info, name)
    else:
        print("\033[1;31m注册出现异常\033[0m")

def quit(client,data):
    ‘‘‘
    程序退出函数
    :param client: 客户端scoket标志
    :param data: 用户数据
    :return: none
    ‘‘‘
    exit()

def main_func(client):
    ‘‘‘
    客户端主菜单函数
    :param client: 客户端scoket标志
    :param data: 数据
    :return: none
    ‘‘‘
    data = "连接成功"
    # client.send("succeed".encode("utf-8"))
    dic = {"1":login,"2":register,"3":quit}
    info = ‘‘‘------用户登录界面------*{0}*
        1、登陆
        2、注册
        3、退出
    ‘‘‘.format(data)
    print("\033[1;33m%s\033[0m"%info)
    what = input("你要干嘛?>>>").strip()
    if what.isdigit() and 0 < int(what) <= len(dic):
        dic.get(what)(client,data)
    else:
        print("\033[1;31m输出错误\033[0m".center(40,"-"))

if __name__ == ‘__main__‘:
    client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    client.connect((HOST,PORT))
    main_func(client)
    client.close()

2、Select FTPServer/bin/Server_start.py

import os,sys
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
from src.main import func

if __name__ == ‘__main__‘:
    func()

3、Select FTPServer/conf/settings.py

import os

basedir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
user_home = "%s/home"%basedir
user_info = "%s/db"%basedir
log_dir = os.path.join(basedir,"log")

HOST = "localhost"
PORT = 6960

4、Select FTPServer/src/common.py

import logging,os,pickle,sys,uuid
frame = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(frame)
from conf import settings

def sys_logging(content,levelname):
    ‘‘‘
    程序记录日志函数
    :param content: 日志的内容
    :param levelname: 日志的等级
    :return: none
    ‘‘‘
    _filename = os.path.join(settings.log_dir,"log_sys.log")
    log = logging.getLogger(_filename)
    logging.basicConfig(filename=_filename,level=logging.INFO,format=‘%(asctime)s-%(levelname)s-%(message)s‘, datefmt=‘%m/%d/%Y %I:%M:%S %p‘)
    if levelname == ‘debug‘:
        logging.debug(content)
    elif levelname == ‘info‘:
        logging.info(content)
    elif levelname == ‘warning‘:
        logging.warning(content)
    elif levelname == ‘error‘:
        logging.error(content)
    elif levelname == ‘critical‘:
        logging.critical(content)

def show(msg,msg_type):
    ‘‘‘
    程序不同信息打印的字体颜色
    :param msg: 打印信息
    :param msg_type: 打印信息的类型
    :return: none
    ‘‘‘
    if msg_type == "info":
        show_msg = "\033[1;35m%s\033[0m"%msg
    elif msg_type == "error":
        show_msg = "\033[1;31m%s\033[0m"%msg
    elif msg_type == "msg":
        show_msg = "\033[1;37m%s\033[0m"%msg
    else:
        show_msg = "\033[1;32m%s\033[0m"%msg
    print(show_msg)
    sys_logging(msg,msg_type)

5、Select FTPServer/src/main.py

import socket,os,sys,selectors
Base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(Base_dir)
from conf import settings
from src.common import show
from src.user import User

sel = selectors.DefaultSelector()

def accept(server, mask):
    ‘‘‘
    新链接的回调函数
    :param server:服务端实例化对象名
    :param mask:链接数
    :return:none
    ‘‘‘
    show("正在监听[%s]地址[%s]端口,等待连接。。。" % (settings.HOST, settings.PORT), "info")
    con, addr = server.accept()
    show("收到{0}的连接请求,正在通信中。。。".format(addr), "info")
    con.setblocking(False)
    sel.register(con, selectors.EVENT_READ, server_method)

def server_method(con,mask):
    ‘‘‘
    服务端数据解析主函数
    :param con:
    :param addr:
    :return:
    ‘‘‘
    # try:
    cmd = con.recv(1024)
    # print(cmd)
    if not cmd:
        sel.unregister(con)
        con.close()
    else:
        # print(cmd)
        data = cmd.decode()
        res = data.split("+")
        name = res[1]
        psd = res[2]
        if res[0] == "login":
            show("收到客户端登陆的请求,正在登陆。。。", "msg")
            user = User(name, psd)
            sign = user.login()
            if sign:
                con.sendall(bytes("Success", encoding="utf-8"))
            else:
                con.sendall(bytes("Failure", encoding="utf-8"))
        elif res[0] == "register":
            show("收到客户端注册的请求,正在注册。。。", "msg")
            user = User(name, psd)
            if user.register():
                con.sendall(bytes("Success", encoding="utf-8"))
            else:
                con.sendall(bytes("Failure", encoding="utf-8"))
        elif res[0] == "view":
            show("收到客户端查看当前目录文件的请求。。。", "msg")
            user = User(name, psd)
            res = user.view_file()
            file = str(res)
            con.sendall(bytes(file, encoding="utf-8"))
            show("当前目录文件查看成功", "info")
        elif res[0] == "upload":
            show("收到客户端上传文件的请求。。。", "msg")
            con.send(bytes("True", encoding="utf-8"))
        elif res[0] == "uploadfile":
            res_length = res[3]
            filename = res[4]
            # print(res_length)
            User.receive(filename, name, res_length, con)
        elif res[0] == "download":
            show("收到客户端下载文件的请求。。。", "msg")
            user = User(name, psd)
            res = str(user.view_file())
            con.sendall(bytes(res, encoding="utf-8"))
        elif res[0] == "downloadfile":
            filename = res[3]
            show("开始下载文件", "msg")
            User.download_file(filename, name, con)
            show("文件下载成功", "info")
    # except Exception as e:
    #     con.close()
    #     show("发生错误:%s"%e,"error")

def func():
    ‘‘‘
    服务端主函数
    :return: none
    ‘‘‘
    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server.bind((settings.HOST,settings.PORT))
    server.listen(100)
    server.setblocking(False)
    sel.register(server, selectors.EVENT_READ, accept)
    while True:
        events = sel.select()
        # print(events)   #11111111111
        for key,mask in events:
            callback = key.data
            # print(key.data, "-----")
            callback(key.fileobj,mask)
            # print(key.fileobj,"-----",mask)

6、Select FTPServer/src/user.py

import os,sys,pickle,socket,time
Base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(Base_dir)
from conf import settings
from src.common import show

class User(object):
    ‘‘‘
    用户类
    ‘‘‘
    def __init__(self,username,psd):
        self.name = username
        self.password = psd
        self.home_path = settings.user_home + "/" +self.name

    def login(self):
        ‘‘‘
        用户登陆方法
        :return:
        ‘‘‘
        user_dic = User.info_read(self.name)
        if user_dic[self.name] == self.password:
            show("登陆成功","info")
            return True
        else:
            show("登陆失败,用户名或密码错误","error")
            return False

    def register(self):
        ‘‘‘
        用户注册方法
        :return:
        ‘‘‘
        dic = {}
        dic[self.name] = self.password
        if User.info_write(self.name,dic):
            show("注册成功","info")
            os.mkdir(self.home_path)
            os.mkdir("%s/others" % self.home_path)
            with open("%s\空白文件" % self.home_path, "w") as f:
                f.write("空白文件")
            return True
        else:
            show("注册失败","error")
            return False

    def view_file(self):
        ‘‘‘
        查看当前目录下文件
        :return: 目录下文件名组成的列表
        ‘‘‘
        if not os.path.exists(self.home_path):
            os.mkdir(self.home_path)
            with open("%s\空白文件"%self.home_path,"w") as f:
                f.write("空白文件")
        for root, dirs, files in os.walk(self.home_path):
            return files

    @staticmethod
    def download_file(filename,name,con):
        ‘‘‘
        下载文件静态方法
        :param filename: 文件名
        :param name: 用户名
        :param con: 标志
        :return: none
        ‘‘‘
        dir = os.path.join(os.path.join(os.path.join(Base_dir, "home"), name), filename)
        with open(dir,"rb") as f:
            data = f.read()
            length = str(len(data))
            # print(type(a))
            con.sendall(bytes(length,encoding="utf-8"))
            time.sleep(1)
            # con.recv(1024)
            # print(con.recv(1024).decode())
            con.sendall(data)

    @staticmethod
    def receive(filename,name,res_length,con):
        ‘‘‘
        接收文件静态方法
        :param filename: 文件名
        :param name: 用户名
        :param con: 标志
        :return: none
        ‘‘‘
        con.send("True".encode("utf-8"))
        # print(filename)
        time.sleep(0.5)
        dir = os.path.join(os.path.join(os.path.join(Base_dir,"home"),name),filename)
        length = 0
        f =  open(dir, "wb")
        while length < int(res_length):
            if int(res_length) - length > 1024:
                size = 1024
            else:
                size = int(res_length) - length
            data = con.recv(size)
            length += len(data)
            # print(length)
            f.write(data)
        if length == int(res_length):
            time.sleep(0.5)
            show("文件下载成功","info")
            f.close()
            return True

    @staticmethod
    def info_read(name):
        ‘‘‘
        读取用户数据的静态方法
        :param name: 用户名
        :return: 字典
        ‘‘‘
        user_dir = os.path.join(settings.user_info,name)
        if os.path.exists(user_dir):
            with open(user_dir,"rb") as f:
                dic = pickle.load(f)
                return dic
        else:
            print("用户数据为空")

    @staticmethod
    def info_write(name,dic):
        ‘‘‘
        写入用户数据的静态方法
        :param name:用户名
        :param dic:用户信息字典
        :return:True
        ‘‘‘
        user_dir = os.path.join(settings.user_info, name)
        with open(user_dir,"wb") as f:
            pickle.dump(dic,f)
            return True

#

  

时间: 2024-09-30 18:10:00

python之路——作业:Select FTP(仅供参考)的相关文章

开发问题---数据库字段前出现“—”(保存留用,仅供参考)

开发时数据调用往往会用到占位符,然而刚开始使用很容易碰见sql语句在SQLServer中查询时显示"-",如下代码: #region 先判断是否有记录,再确定使用哪条命令 //查询数据库 20140713 commandText = "use zzbjcdzz select *" + "from [T_VillageBasicInfo] " + "where ltrim(rtrim([code]))='{0}' "; //注意

Ubuntu 12.04 分区方案(仅供参考)

Ubuntu 12.04 分区方案(仅供参考) 总空间大小:50G 目录 建议大小 实际大小 格式 描述 / 10G~20G 10G ext4 根目录 swap <2048M 1G swap 交换空间 /boot 200M左右 100M ext4 Linux的内核及引导系统程序所需要的文件,比如 vmlinuz initrd.img文件都位于这个目录中.在一般情况下,GRUB或LILO系统引导管理器也位于这个目录:启动撞在文件存放位置,如kernels,initrd,grub. /tmp 5G左

四套写入方案(仅供参考)

四套写入方案 第一套:字节流读取写入方案 FileInputStream :字节流方式读取文本文件 FileOutputStream:字节流写入硬盘 第二套:字符流读取写入方案 FileReader:字符流读取文本 FileWriter:字符流写入文本 第三套: BufferedReader:自定义缓存大小 BufferedWriter:写入文本 一般和FileReader和FileWriter结合使用 第四套:可以读取二进制(img图片等 ) DataInputStream:将本地的img加载

信息与通信工程——重要国际学术会议和国际顶级期刊(仅供参考)

一.信息与通信工程的重要国际学术会议 主要包含两类: A类会议:本学科最顶尖级水平的国际会议: B类会议:学术水平较高.组织工作成熟.按一定时间间隔系列性召开的国际会议. A类会议(序号不表示优先顺序) 序号 / 英文名称 / 英文简称 / 中文名称 / 备注 1.IEEE International Conference on Acoustics, Speech and Signal Processing /  ICASAP /     IEEE 声学.语音和信号处理国际会议 2.IEEE I

Unity上一页下一页切换功能实现源码(仅供参考)

在做项目时我们有时需要实现切换上一页下一页图片,切换上一首下一首歌曲等等类似的功能.这里写了个简单的实现源码(仅供参考),要是有更好的方法欢迎提出来,共同进步~ 以切换上一页下一页图片为例: using UnityEngine; using System.Collections; using UnityEngine.UI; public class PanoramaManager : MonoBehaviour { //图片存放数组 Texture2D[] arr; //下一张按钮计数索引 in

Django开发的简单CMDB系统(仅供参考)

自己基于django开发的一个简单机房机柜CMDB系统,仅供参考.欢迎在下面留言,提出修改意见. 可实现增删改查. 权限未做,很多功能都没做,只做一个最基本的,初学. 前端模板用的inspinia2.5,和jumpserver用的一样的模块,所以看着差不多.模板可自行百度搜索. 放到pycharm或者linux环境下,配置好,运行就可以. domo 登录:http://42.62.6.54:8001/index.html  ,默认用户名hequan,密码123456. 下载链接:http://p

如何有效防止DEDE织梦系统被挂木马安全设置(仅供参考)

尊敬的客户,您好!     感谢广大客户对我司工作的信任和支持!      我司在最近的一个多月内陆续发现多起因 DedeCMS 安全漏洞造成网站被上传恶意脚本的事件,入侵者可利用恶意脚本对外发送大量数据包,严重占用CPU资源与服务器带宽,影响极为恶劣.为保证服务稳定,即日起一旦发现网站存在此类恶意脚本,我们将立即暂停该网站的服务直到问题修复.如果您正在使用 DedeCMS,请立即检查是否已经存在恶意脚本,并更新程序到最新版本或应用相关补丁.     迄今为止,我们发现的恶意脚本文件有    

mysql 千万级数据查询效率实践,分析 mysql查询优化实践--本文只做了一部分,仅供参考

数据量, 1300万的表加上112万的表 注意: 本文只做了部分优化,并不全面,仅供参考, 欢迎指点. 请移步tim查看,因为写的时候在tim写的,粘贴过来截图有问题,就直接上链接了. https://823948977.docs.qq.com/T5e6dBYLoZz?opendocxfrom=tim 文章内容类似截图:

单相变频电源的功能特点--深圳市中港扬盛仅供参考

变频电源的种类分为单相和三相变频,其在电压及功率上都有不同的作用和特点.今天大家分享的是关于中港扬盛的单相变频电源的一些特点: 1.能够有效的抗干扰作用:比如通过Y/△接线的隔离后,就能够阻止一部分谐波的传输:2.能够阻抗变换作用:主要是增加系统阻抗,这样就能使保护装置等容易配合:3.能够稳定系统电压的作用:比如像在启动大负荷设备的时候,能够减少启动时大电流对系统电压的影响:4.能够防止系统接地的作用:当隔离负荷侧发生单相接地时,不会造成整个系统单相接地:5.能够降低短路电流:当负荷侧发生短路事

短信接口与短信平台收费标准----速码云仅供参考

就目前来说短信接口 价格参考 行业收费也基本上没有个固定的标准的价格,都是看各个公司自己的通道套餐跑的量和公司的运营成本结合预算后最终才来制定一套给客户的价格,所以说在短信行业里面短信公司获取的利润是非常小的,除了运营商的短信通道费用之外还有公司的人员成本,公司的场地,服务器和系统等等一切费用,一般几分钱的短信利润大的可能是1-2分钱,如果客户购买得多的话那么几个就会很低,那么利润就有可能是几厘钱了,所以短信公司也是薄利多销,下面就提供一些短信接口行业一般的短信价格给大家参考. 套餐1,比如购买