高级FTP服务器开发

要求:

1. 用户加密认证

2. 多用户同时登陆

3. 每个用户有自己的家目录且只能访问自己的家目录

4. 对用户进行磁盘配额、不同用户配额可不同

5. 用户可以登陆server后,可切换目录

6. 查看当前目录下文件

7. 上传下载文件,保证文件一致性

8. 传输过程中现实进度条

9. 支持断点续传

路径如下

代码

import socket
import pickle
import hashlib
import sys
import time
import os
A = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
class Ftp_client(object):
    def __init__(self):
        self.client = socket.socket()
    def help(self):
        ‘‘‘
        帮助说明
        :return:
        ‘‘‘
        print(‘‘‘请输入正确的指令:
        ls: 查看根目录下文件
        cd: 切换目录
        download: 下载文件
        upload:上文件
        mkdir:新建立文件夹
                ‘‘‘)
    def connet(self, ip, port):
        ‘‘‘
        链接服务器
        :param ip:
        :param port:
        :return:
        ‘‘‘
        self.client.connect((ip, port))
        data = self.client.recv(1024)
        print(data.decode())
        self.main()
        self.ftp_main()
    def login(self):
        ‘‘‘
        登录
        :return:
        ‘‘‘
        name = input(‘请输入姓名‘).lower()
        password = input(‘请输入密码‘)
        dict = {‘name‘: name, ‘password‘: password}
        self.client.sendall(pickle.dumps(dict))
        data = self.client.recv(1024)
        print(data.decode())
        if data.decode()==‘输入有误‘:
            return False
    def register(self):
        ‘‘‘
        注册
        :return:
        ‘‘‘
        while True:
            a = input(‘请输入注册哪种用户: 1: 普通用户(可用空间10M), 2: VIP用户(可用30M)‘)
            if a ==‘1‘:
                space = 10485760
                break
            elif a== ‘2‘:
                space = 31457280
                break
            else:
                print(‘输入有误‘)
                continue
        name = input(‘请输入姓名‘).lower()
        pd = input(‘请输入密码‘)
        dict = {‘name‘: name, ‘password‘: pd, ‘space‘: space}
        self.client.sendall(pickle.dumps(dict))
        data = self.client.recv(1024)
        print(data.decode())
        if data.decode()== ‘用户名已存在,请重新输入‘:
            return False

    def main(self):
        while True:
            a = input(‘请输入 1. 用户登录 2. 用户注册 3.退出‘)
            if a == ‘1‘:
                self.client.sendall(‘login‘.encode())
                res = self.login()
            elif a == ‘2‘:
                self.client.sendall(‘register‘.encode())
                res = self.register()
            elif a == ‘3‘:
                exit()
            else:
                print(‘输入有误‘)
                continue
            if res is False:
                    continue
            else:
                break

    def download(self):
        ‘‘‘
        下载
        :return:
        ‘‘‘
        while True:
            data = self.client.recv(1024)
            choose = input(‘文件所在路径 1 根目录 2 子目录‘)
            if choose == ‘1‘:
                path = ‘1‘
                break
            elif choose ==‘2‘:
                path = input(‘请输入路径,子路径用 / 分隔隔开‘) # 根目录不用输入
                break
            else:
                print(‘输入有误‘)
                continue
        self.client.sendall(path.encode())
        data = self.client.recv(1024)
        filename = input(‘请输入下载文件名‘)
        self.client.sendall(filename.encode())
        size = self.client.recv(1024).decode()
        if size == ‘该文件不存在‘:
            print (‘该文件不存在‘)
            return False
        else:
            size = int(size)
            if os.path.exists(os.path.join(A, ‘db‘, filename)):
                r_size = int(os.path.getsize(os.path.join(A, ‘db‘, filename)))#存在文件的size
                while True:
                    choose = input(‘文件已存在, 1 重新下载 2 停止下载 3 新起名再下载 4 继续下载‘)
                    if choose == ‘2‘:
                        dic={}
                        dic[‘choose‘] = choose
                        self.client.sendall(pickle.dumps(dic))
                        return False
                    elif choose == ‘1‘:
                        f = open(os.path.join(A, ‘db‘,filename),‘wb‘)
                        r_size = 0
                        break
                    elif choose == ‘3‘:
                        name = input(‘请输入新文件名‘)
                        f = open(os.path.join(A, ‘db‘,name),‘wb‘)
                        r_size = 0
                        break
                    elif choose == ‘4‘:
                        f = open(os.path.join(A, ‘db‘,filename),‘ab‘)
                        break
                    else:
                        print(‘输入有误,请重新输入‘)
                dic={}
                dic[‘choose‘] = choose
                dic[‘size‘] = r_size
                self.client.sendall(pickle.dumps(dic))
            else:
                r_size = 0
                f = open(os.path.join(A, ‘db‘, filename),‘xb‘)

            if size == 0:
                f.close()
                print(‘接收完成‘)
            else:
                while  r_size < size:
                    file = self.client.recv(1024)
                    f.write(file)
                    f.flush() #文件强行写入file,预防中途中断
                    r_size += len(file)
                    view_bar(r_size, size)
                    time.sleep(0.1)
                else:
                    print(‘接收完成‘)
                    f.close()

    def upload(self):
        filename = input(‘请输入上传的文件名‘)
        if os.path.exists(os.path.join(A, ‘db‘, filename)):
            size = os.path.getsize(os.path.join(A, ‘db‘, filename)) #文件size
            path = input(‘请输入上传的路径,子路径用 / 分隔隔开, h为根目录‘)
            dic = {}
            dic[‘filename‘] = filename
            dic[‘size‘] = size
            dic[‘path‘] = path
            self.client.sendall(pickle.dumps(dic))
            f =  open(os.path.join(A, ‘db‘, filename), ‘rb‘)
        else:
            print (‘此文件不存在‘)
            return False
        data = self.client.recv(1024)
        ls = pickle.loads(data) #ls[2]: ;
        if ls[-1]==‘1‘: #ls[-1]:检查下载的路径是否存在
            print (‘此路径不存在‘)
            return False
        if ls[0] == ‘0‘:#ls[0]:检查空间够不够;
            print (‘空间不足,不能上传‘)

        else:
            if ls[1] == ‘0‘: #ls[1]:检查下载是否存在
                while True:
                    a = input(‘文件已存在, 1 重新下载 2 停止下载 3 新起名再下载 4 继续下载‘)
                    f_ls = []
                    f_ls.append(a)
                    if a == ‘1‘:
                        break
                    elif a == ‘2‘:
                        return False
                    elif a ==‘3‘:
                        f_name = input(‘请输入新文件名‘)
                        f_ls.append(f_name)
                        break
                    elif a==‘4‘:
                        l_size = ls[2] #ls[2]:已下载的文件大小
                        f.seek(l_size) #把指针放到已下载的地方,继续下载
                        break
                    else:
                        print (‘输入有误‘)
            else:
                f_ls = []
                f_ls.append(‘5‘) # 5:下载文件不存在
            self.client.sendall(pickle.dumps(f_ls))
            data = self.client.recv(1024).decode()
            print (data)
            for line in f:
                self.client.sendall(line)
                num = f.tell() #查看文件上传位置
                view_bar(num, size)
                time.sleep(0.1)
            f.close()
            print (‘接收完成‘)
            return False

    def ls(self):
        data = self.client.recv(1024)
        if data ==‘0‘.encode():
            print(‘此目录为空‘)
        elif data ==‘1‘.encode():
            print(‘此文件不存在‘)
        else:
            ls = pickle.loads(data)
            print(‘此文件里有:‘)
            for i in ls:
                print(i)

    def mkdir(self):
        name = input(‘请输入文件夹名‘)
        self.client.sendall(name.encode())
        data = self.client.recv(1024).decode()
        print(data)

    def cd(self):
        name = input(‘请输入路径,子路径用 / 分隔隔开‘) # 根目录不用输入
        self.client.sendall(name.encode())
        path = self.client.recv(1024).decode()

        if path == ‘0‘:
            print (‘此目录不存在‘)
            return False
        else:
            print (‘所在文件夹路径为 %s‘ % path)
        self.client.sendall(‘ok‘.encode())
        data = self.client.recv(1024)
        if data ==‘0‘.encode():
            print(‘此目录为空‘)
        else:
            ls = pickle.loads(data)
            print(‘此文件里有:‘)
            for i in ls:
                print(i)

    def ftp_main(self):
        while True:
            a = input(‘请输入相应的指令, help:查询, exit:退出‘)
            if hasattr(self, a):
                self.client.sendall(a.encode())
                func = getattr(self, a)
                func()
            elif a == ‘exit‘:
                exit()
            else:
                self.help()
                continue

def view_bar(num, total):
    ‘‘‘进度条‘‘‘
    rate = float(num) / float(total)
    rate_num = int(rate * 100)
    r = ‘\r%d%%‘ % (rate_num, ) #\r 回到到开头
    sys.stdout.write(r)
    sys.stdout.flush()  #删除记录

ftp = Ftp_client()
ftp.connet(‘localhost‘, 9999)

client

import socketserver
import pickle
import os
import time
A = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            try:
                self.request.sendall(‘链接成功‘.encode())
                while True:
                    data = self.request.recv(1024).decode()
                    if data ==‘login‘:
                        a = self.login()
                    else:
                        a = self.register() #a为 list,[0]是name,[1]是可用空间
                    if a is False:
                        continue
                    else:
                        while True:
                            data = self.request.recv(1024)
                            func = getattr(self, data.decode())
                            func(a)
            except Exception: #检查客户端是否连接正常
                print(‘客户端断开‘)
                break

    def login(self):
        db_dict = pickle.load(open(os.path.join(A, ‘db‘, ‘register‘),‘rb‘))
        self.data = self.request.recv(1024)
        dict = pickle.loads(self.data)
        if dict[‘name‘] in db_dict:
            if dict[‘password‘]==db_dict[dict[‘name‘]][0]:
                self.request.sendall(‘登录成功‘.encode())
                return [dict[‘name‘], db_dict[dict[‘name‘]][1]] #返回用户名,用户可用空间
            else:
                self.request.sendall(‘输入有误‘.encode())
                return False
        else:
            self.request.sendall(‘输入有误‘.encode())
            return False
    def register(self):
        dict = pickle.loads(self.request.recv(1024))
        print (dict)
        if os.path.exists(os.path.join(A, ‘db‘, dict[‘name‘])):
            self.request.sendall(‘用户名已存在,请重新输入‘.encode())
            return False
        else:
            self.request.sendall(‘注册成功‘.encode())
            os.makedirs(os.path.join(A, ‘db‘, dict[‘name‘]))
            # n_dict ={}
            n_dict = pickle.load(open(os.path.join(A, ‘db‘, ‘register‘), ‘rb‘))
            print (1)
            print (n_dict)
            n_dict[dict[‘name‘]]=[dict[‘password‘],int(dict[‘space‘])] #存储格式为{姓名:[密码,可用空间大少]}
            print (n_dict)
            pickle.dump(n_dict,open(os.path.join(A, ‘db‘, ‘register‘), ‘wb‘))
            return [dict[‘name‘], int(dict[‘space‘])]
    def help(self, a):
        return False
    def upload(self, list):
        name = list[0]
        b_path = os.path.join(A, ‘db‘, name) #自己的根目录
        h_size = int(list[1]) #自己可用的空间大小
        data = self.request.recv(1024)
        dic = pickle.loads(data)
        f_size = int(dic[‘size‘]) #上传文件大小
        filename = dic[‘filename‘]
        path = dic[‘path‘]
        s_ls = []
        if h_size < f_size:
            a = ‘0‘ #空间不足
            s_ls.append(a)
        else:
            a = ‘1‘
            s_ls.append(a)
        if path==‘h‘: #存在根目录
            l_path =os.path.join(b_path,filename)
        else:
            res = path.split(‘/‘)
            print (res)
            for i in res:
                b_path = os.path.join(b_path, i) #合拼成子目录
            l_path = os.path.join(b_path,filename) #文件路径

        if os.path.exists(l_path):
            b = ‘0‘ #文件已存在
            file_size = os.path.getsize(l_path)
            s_ls.append(b)
            s_ls.append(file_size)
        else:
            b = ‘1‘
            s_ls.append(b)
        if os.path.exists(b_path):
            c = ‘0‘
        else:
            c=‘1‘#文件夹不存在,可以结束
            s_ls.append(c)
            self.request.sendall(pickle.dumps(s_ls))
            return False
        s_ls.append(c)
        self.request.sendall(pickle.dumps(s_ls))
        f_ls = pickle.loads(self.request.recv(1024))#文件以什么方式打开
        self.request.sendall(‘准备开始‘.encode())
        if f_ls[0] ==‘1‘:
            f = open(l_path,‘wb‘)
            file_size = 0
        elif f_ls[0]==‘2‘:
            return False
        elif f_ls[0]==‘3‘:#文件名另起
            filename = f_ls[1]
            l_path = os.path.join(b_path,filename)
            f = open(l_path,‘wb‘)
            file_size = 0
        elif f_ls[0]==‘4‘:
            f = open(l_path,‘ab‘)
        else:
            f = open(l_path,‘xb‘)
            file_size = 0
        if f_size == 0:
            f.close()
            return False
        else:
            while file_size< f_size:
                line = self.request.recv(1024)
                f.write(line)
                f.flush()
                file_size += len(line)
            else:
                f.close()
                l_dict = pickle.load(open(os.path.join(A, ‘db‘, ‘register‘), ‘rb‘))
                l_dict[name][1] = h_size - f_size #修改已用空间
                pickle.dump(l_dict, open(os.path.join(A, ‘db‘, ‘register‘), ‘wb‘))
                return False

    def download(self, list):
        self.request.sendall(‘ok‘.encode())
        path = self.request.recv(1024).decode() #检查文件存在子目录或根目录
        self.request.sendall(‘check‘.encode())
        filename = self.request.recv(1024).decode()
        name = list[0]
        if path == ‘1‘:
            l_path = os.path.join(A, ‘db‘, name,filename)
        else:
            data = path.split(‘/‘)
            pathname = os.path.join(A, ‘db‘, name)
            for i in data:
                pathname = os.path.join(pathname, i) #合拼子目录
            l_path = os.path.join(pathname,filename)
            print (l_path)
        if os.path.exists(l_path):
            f = open(l_path, ‘rb‘)
            size = os.path.getsize(l_path) #检查文件
            self.request.sendall(str(size).encode()) #要以字符串格式传数字
            data = self.request.recv(1024)
            dic = pickle.loads(data)
            if dic[‘choose‘]==‘2‘:
                return False
            elif dic[‘choose‘]==‘4‘:
                f.seek(int(dic[‘size‘])) #把指针定位到已下载的地方
            for line in f:
                self.request.sendall(line)
            f.close()
            print (‘done‘)
        else:
            self.request.sendall(‘该文件不存在‘.encode())

    def ls(self, list):
        name = list[0]
        ls = os.listdir(os.path.join(A, ‘db‘, name))
        if len(ls)==0:
            self.request.sendall(‘0‘.encode())
        else:
            a = []
            for i in ls:
                a.append(i) #把存在的文件放入list
            self.request.sendall(pickle.dumps(a))
    def cd(self, list):
        data = self.request.recv(1024).decode()
        name = list[0]
        path = os.path.join(A, ‘db‘, name) #根目录
        path_ls = data.split(‘/‘)
        for i in path_ls:
            path = os.path.join(path, i) #合拼子目录
        print (path)
        if os.path.exists(path) is False:
            print (1)
            path = ‘0‘
            self.request.sendall(path.encode())
            return False
        ls = os.listdir(path)
        self.request.sendall(path.encode())
        data = self.request.recv(1024)
        if len(ls)==0:
            self.request.sendall(‘0‘.encode())
        else:
            a = []
            for i in ls:
                a.append(i)
            self.request.sendall(pickle.dumps(a))

    def mkdir(self, a):
        filename = self.request.recv(1024).decode()
        name = a[0]
        if os.path.exists(os.path.join(A, ‘db‘, name,filename)): #检查路径是否存在
            self.request.sendall(‘文件夹已存在‘.encode())
        else:
            os.makedirs(os.path.join(A, ‘db‘, name, filename))
            self.request.sendall(‘已建好‘.encode())

host, port = ‘localhost‘,  9999
server = socketserver.ThreadingTCPServer((host, port), MyTCPHandler)
server.serve_forever()

server

时间: 2024-10-13 22:33:07

高级FTP服务器开发的相关文章

(转)python高级FTP

原文地址:http://www.itnose.net/detail/6754889.html高级FTP服务器1. 用户加密认证2. 多用户同时登陆3. 每个用户有自己的家目录且只能访问自己的家目录4. 对用户进行磁盘配额.不同用户配额可不同5. 用户可以登陆server后,可切换目录6. 查看当前目录下文件7. 上传下载文件,保证文件一致性8. 传输过程中现实进度条9.支持断点续传10.用户操作日志 服务端 启动参数 start客户端 启动参数 -s localhost -P 9500 程序结构

python第四十八天--高级FTP

高级FTP服务器1. 用户加密认证2. 多用户同时登陆3. 每个用户有自己的家目录且只能访问自己的家目录4. 对用户进行磁盘配额.不同用户配额可不同5. 用户可以登陆server后,可切换目录6. 查看当前目录下文件7. 上传下载文件,保证文件一致性8. 传输过程中现实进度条9.支持断点续传10.用户操作日志 服务端 启动参数 start客户端 启动参数 -s localhost -P 9500 程序结构:seniorFTP/#综合目录|- - -ftp_client/#客户端程序目录| |-

python开发ftp服务器第一天(pyftpdlib)

学习了大约快一个月的python,现在开始有意识做一些项目. 据我了解,python现在更多的是用于自动化运维方面,例如做一些服务器上审计堡垒机,分布式监控,还有做web的后台开发. 今天想在实验室搭建一个ftp服务器,用来分享一些资料,于是就想到了利用python来进行开发. ftp服务器的本质还是利用socket编程来实现,只不过遵循特定的协议而已,我查了一下协议是RFC959. 当然为了不重复造轮子,先看看有没有开源的lib,百度一下找到了pyftpdlib这个库,查看了一下这个库,发现代

C#实现开发windows服务实现自动从FTP服务器下载文件(自行设置分/时执行)

最近在做一个每天定点从FTP自动下载节目.xml并更新到数据库的功能.首先想到用 FileSystemWatcher来监控下载到某个目录中的文件是否发生改变,如果改变就执行相应的操作,然后用timer来设置隔多长时间来下载.后来又想想了.用windwos服务来实现吧. 效果图: 执行的Log日志: INFO-2016/5/24 0:30:07--日志内容为:0/30/7进行time触发 INFO-2016/5/24 1:30:07--日志内容为:1/30/7进行time触发 INFO-2016/

汉澳Sinox2014X64server高级桌面服务器版操作系统发布

汉澳Sinox2014X64server高级桌面服务器版操作系统发布 当你在现代城市夜空中看到一道闪电,屏幕中央闪过几个图形,转眼间变成美轮美奂的紫色空中天国,说明你来到了汉澳sinox2014世界! 在汉澳sinox2013基础上开发的64位汉澳sinox将更加先进,充分利用计算机的硬件资源,更多的软件,还支持硬件厂家驱动程序下载安装. 汉澳Sinox2014X64server高级64位桌面服务器版操作系统发布 下载地址 ftp://ftp.sinox.org/sinox2014x64serv

汉澳Sinox2014X64server高级桌面服务器版操作系统公布

汉澳Sinox2014X64server高级桌面服务器版操作系统公布 当你在现代城市夜空中看到一道闪电.屏幕中央闪过几个图形,转眼间变成美轮美奂的紫色空中天国,说明你来到了汉澳sinox2014世界! 在汉澳sinox2013基础上开发的64位汉澳sinox将更加先进,充分利用计算机的硬件资源,很多其它的软件.还支持硬件厂家驱动程序下载安装. 汉澳Sinox2014X64server高级64位桌面服务器版操作系统公布 下载地址 大家快去下载,用迅雷快速下载 下载地址 ftp://sinox.or

Linux下使用curlftpfs挂载远程FTP服务器

步骤: 1,前提你得有一个FTP的服务器,账户,密码 2,安装curlftpfs 工具 3,挂载 4,乱码问题解决 5,遍历FTP 6,在里面找你想要的信息 废话不多说,开始搞! 1,发现FTP文件服务器 无意在网上看到一个ftp,大概看了一下,里面的信息有点意思 FTP地址:ftp://ftp1.linuxidc.com 用户名:ftp1.linuxidc.com 密码:www.linuxidc.com 2,安装工具,一键完成,没什么要说的 apt-get -y install curlftp

centos yum安装与配置vsFTPd FTP服务器(转)

vsftpd作为FTP服务器,在Linux系统中是非常常用的.下面我们介绍如何在centos系统上安装vsftp. 什么是vsftpd vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序.特点是小巧轻快,安全易用. vsftpd 的名字代表"very secure FTP daemon", 安全是它的开发者 Chris Evans 考虑的首要问题之一.在这个 FTP 服务器设计开发的最开始的时候,高安全性就是一个目标. 安装vsftpd 1.以管理员(root)身份执行以

Python一秒搭建ftp服务器,帮助你在局域网共享文件【华为云技术分享】

“老板 来碗面” “要啥面?” “内牛满面..” 最近项目上的事情弄得人心累,本来是帮着兄弟项目写套入口代码,搞着搞着就被拉着入坑了.搞开发的都知道,最怕弄这种项目portal的东西,你调用一堆东西,结果各种调用报错都反馈到你这里,导致的结果就是除了啥问题都找你. 最形象的比喻就是,眼前一栋楼,你是看门的.电梯坏了找你.住户被盗了找你.连谁家下水不通了也找你,各种无厘头的破事儿,我就想送出一张图… 共享文件 熟悉Python的朋友们都知道,python自带了一个Simple HTTP Serve