首页 > 代码库 > 模拟百度云盘版的ftp

模拟百度云盘版的ftp

思路:
一、分两个大的文件夹,一个是客户端,一个服务端的

二、实现的功能

    1.    登陆--对用户名的合法性进行检测(实验账户:alex,123)
        
        注册--设置账户,其中网盘列表设置为空,刚注册的用户给到50下载豆

        规则:
            
            用户上传文件是上传到服务端的共享文件库里,同时会添加到自己的网盘里,
            上传一个文件就可以奖励50下载豆,并自己上传的文件以后下载不用下载豆

            用户去找资源,其实就是把服务端的共享文件库陈列给客户看,客户如果把
            服务端的资源文件添加到自己的网盘,必须消耗20下载豆

            用户下载不用消耗下载豆,但是只能从自己的网盘里下载

    2.进入到FTP客户可以选择:

        上传--

            遍历自己本地文件库,选择上传,上传过程中显示进度条(支持断点续传)
            
        下载--

            遍历自己的网盘,选择下载,下载过程中显示进度条(支持断点下载)

        找资源--

            遍历服务端的共享文件库,选择添加到自己的网盘

        查看我的网盘--

            遍历自己的网盘展示

 

流程图

技术分享

 

代码实现

目录:

技术分享

client端:

  client_main.py

import osimport syspat = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))sys.path.append(pat)from config import Configimport socketimport timeimport jsondef main():    #连接服务器    ip_port = (‘127.0.0.1‘,8009)    sk = socket.socket()    sk.connect(ip_port)    #接收欢迎信息    bt = sk.recv(1024)    print(str(bt,encoding=‘utf-8‘))    flag1 = 1    while flag1:        # 让客户选择操作        print(‘\t1\t登陆\n\t2\t注册‘)        choose = input(‘请选择序号选择你的操作:‘)        if choose == ‘2‘:            sk.sendall(bytes(choose,encoding=‘utf-8‘))            print(‘注册页面!‘)            while True:                reg_usr = input(‘请输入注册用户名:‘)                sk.sendall(bytes(reg_usr,encoding=‘utf-8‘))                ret = str(sk.recv(1024),encoding=‘utf-8‘)                if ret == ‘合法‘:                    reg_pwd = input(‘请输入注册密码:‘)                    sk.sendall(bytes(reg_pwd,encoding=‘utf-8‘))                    bt = sk.recv(1024)                    print(str(bt,encoding=‘utf-8‘))                    break                else:                    print(ret)        elif choose == ‘1‘:            sk.sendall(bytes(choose, encoding=‘utf-8‘))            print(‘登陆页面!‘)            flag2 = 1            while flag2:                landed_usr = input(‘请输入用户名:‘)                sk.sendall(bytes(landed_usr,encoding=‘utf-8‘))                ret = str(sk.recv(1024), encoding=‘utf-8‘)                if ret == ‘存在‘:                    while True:                        landed_pwd = input(‘请输入密码:‘)                        sk.sendall(bytes(landed_pwd,encoding=‘utf-8‘))                        bt = sk.recv(1024)                        if str(bt,encoding=‘utf-8‘) == ‘yes‘:                            print(‘登陆成功!‘)                            flag1 = 0                            flag2 = 0                            enter_flag = 1                            break                        else:                            print(str(bt, encoding=‘utf-8‘))                else:                    print(‘用户名不存在!请重新输入!‘)        else:            print(‘输入有误!请重新输入!‘)    #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++    while enter_flag:        print(‘\n\t1\t上传\n‘              ‘\t2\t下载\n‘              ‘\t3\t找资源\n‘              ‘\t4\t查看我的网盘\n‘)        choose = input(‘请选择你接下来的操作(输入q退出):‘)        #把客户的选择发过去        sk.sendall(bytes(choose, encoding=‘utf-8‘))        if choose == ‘1‘:            #遍历本地文件,并让客户选择            for k,file_name in enumerate(Config.local_file_list,1):                print(k,file_name)            m = input(‘请选择你要上传的文件:‘)            file_name = Config.local_file_list[int(m)-1]            print(file_name)            #把文件名发过去            sk.sendall(bytes(file_name,encoding=‘utf-8‘))            print(‘文件名已发过去!‘)            #接收检测的文件大小            file_size = str(sk.recv(1024),encoding=‘utf-8‘)            print(‘文件大小已收到!‘,file_size)            file_name_path = os.path.join(Config.PATH,file_name)            all_size = os.stat(file_name_path).st_size            print(‘总大小:‘,all_size)            if all_size != int(file_size):                with open(file_name_path,‘rb‘) as f:                    num = int(file_size)                    f.seek(num)                    for line in f:                        sk.sendall(line)                        file_size = str(sk.recv(1024),encoding=‘utf-8‘)                        sys.stdout.write(‘\r‘)  # 每一次清空原行                        sys.stdout.write(‘%s%% |%s‘ % (int( int(file_size)/ all_size * 100),                                                       int(int(file_size) / all_size / 2 * 100) * ‘*‘))                        sys.stdout.flush()  # 强制刷新缓冲区                        time.sleep(0.3)                    sk.sendall(bytes(‘1‘,encoding=‘utf-8‘))                    print(‘\n上传完毕!‘)            else:                print(‘你要上传的文件已存在!‘)        elif choose == ‘2‘:            s = str(sk.recv(1024), encoding=‘utf-8‘)            my_wangpan = json.loads(s)            print(‘我的网盘:‘)            for n, file_na in enumerate(my_wangpan, 1):                print(n, file_na)            load_choose = input(‘请输入序号选择你要下载的文件:‘)            sk.sendall(bytes(load_choose,encoding=‘utf-8‘))            all_size = str(sk.recv(1024),encoding=‘utf-8‘)            print(type(all_size),all_size)            load_file_name = my_wangpan[int(load_choose) - 1]            pth = os.path.join(Config.PATH, load_file_name)            if load_file_name in Config.local_file_list:                file_size = os.stat(pth).st_size                if str(file_size) == all_size:                    sk.sendall(bytes(‘下载过‘,encoding=‘utf-8‘))                    sk.recv(1024)                    print(‘你本地文件里已有要下载的文件!‘)                else:                    print(‘继续下载...‘)                    sk.sendall(bytes(‘下载了一点点‘,encoding=‘utf-8‘))                    sk.recv(1024)                    sk.sendall(bytes(str(file_size),encoding=‘utf-8‘))                    with open(pth,‘ab‘) as f:                        while True:                            bt = sk.recv(1024)                            if int(file_size / int(all_size)) == 1:                                break                            else:                                f.write(bt)                                file_size += len(bt)                                sys.stdout.write(‘\r‘)  # 每一次清空原行                                sys.stdout.write(‘%s%% |%s‘ % (int(file_size / int(all_size) * 100),                                                               int(file_size / int(all_size) / 2 * 100) * ‘*‘))                                sys.stdout.flush()  # 强制刷新缓冲区                                time.sleep(0.3)                    print(‘\n下载完成!‘)            else:                print(‘开始下载...‘)                sk.sendall(bytes(‘没下载‘,encoding=‘utf-8‘))                sk.recv(1024)                file_size = 0                sk.sendall(bytes(‘0‘,encoding=‘utf-8‘))                with open(pth, ‘wb‘) as f:                    while True:                        bt = sk.recv(1024)                        if int(file_size / int(all_size)) == 1:                            break                        else:                            f.write(bt)                            file_size += len(bt)                            sys.stdout.write(‘\r‘)  # 每一次清空原行                            sys.stdout.write(‘%s%% |%s‘ % (int(file_size / int(all_size) * 100),                                                           int(file_size / int(all_size) / 2 * 100) * ‘*‘))                            sys.stdout.flush()  # 强制刷新缓冲区                            time.sleep(0.3)                print(‘下载完成!‘)        elif choose == ‘3‘:            print(‘进入!‘)            s = str(sk.recv(1024),encoding=‘utf-8‘)            print(‘收到json字符‘)            li = json.loads(s)            print(‘资源如下:‘)            for m,file_name in enumerate(li,1):                print(m,file_name)            choose = input(‘请选择序号决定你想要添加到网盘的文件(添加一个文件减少20下载豆):‘)            sk.sendall(bytes(choose,encoding=‘utf-8‘))            print(str(sk.recv(1024),encoding=‘utf-8‘))        elif choose == ‘4‘:            s = str(sk.recv(1024),encoding=‘utf-8‘)            my_wangpan = json.loads(s)            print(‘我的网盘:‘)            for n,file_na in enumerate(my_wangpan,1):                print(n,file_na)        elif choose.lower() == ‘q‘:            exit()        else:            print(‘你输入有误!请重新输入!‘)if __name__ == ‘__main__‘:    main()

   config.py

import osimport syspat = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))PATH = os.path.join(pat,‘db‘)local_file_list = os.listdir(PATH)

 

server端

  server_main.py

import osimport syspat = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))sys.path.append(pat)from lib import accountfrom config import Configimport socketserverimport jsonimport timeimport pickleclass MyServer(socketserver.BaseRequestHandler):    def handle(self):        # print self.request,self.client_address,self.server        conn = self.request        conn.sendall(bytes(‘欢迎来到百度云盘!‘,encoding=‘utf-8‘))        flag1 = 1        while flag1:            choose = str(conn.recv(1024), encoding=‘utf-8‘)            if choose == ‘2‘:                while True:                    reg_usr = str(conn.recv(1024),encoding=‘utf-8‘)                    ret = account.usr_ver(reg_usr)                    conn.sendall(bytes(ret,encoding=‘utf-8‘))                    if ret == ‘合法‘:                        reg_pwd = str(conn.recv(1024),encoding=‘utf-8‘)                        hash_pwd = account.encrypt(reg_pwd)                        ob = account.Account()                        ob.registered(reg_usr,hash_pwd)                        account.info_add(ob)                        conn.sendall(bytes(‘注册成功!‘,encoding=‘utf-8‘))                        break            elif choose == ‘1‘:                flag2 = 1                while flag2:                    landed_usr = str(conn.recv(1024),encoding=‘utf-8‘)                    ret = account.land_usr_ver(landed_usr)                    conn.sendall(bytes(ret,encoding=‘utf-8‘))                    if ret == ‘存在‘:                        while True:                            landed_pwd = str(conn.recv(1024),encoding=‘utf-8‘)                            obj = account.landed_ver(landed_usr,landed_pwd)                            if isinstance(obj,account.Account):                                conn.sendall(bytes(‘yes‘, encoding=‘utf-8‘))                                flag1 = 0                                flag2 = 0                                break                            else:                                conn.sendall(bytes(obj, encoding=‘utf-8‘))        #########################################################################################        while True:            #接收客户的操作选择            choose = str(conn.recv(1024),encoding=‘utf-8‘)            if choose == ‘1‘:                #接收客户发来需要上传的文件名                file_name = str(conn.recv(1024),encoding=‘utf-8‘)                pat = os.path.join(Config.PATH,file_name)                #判断上传的文件是否存在                if file_name in Config.shared_file_list:                    file_size = os.stat(pat).st_size                    #对存在的文件,检测大小,把值传过去                    conn.sendall(bytes(str(file_size),encoding=‘utf-8‘))                    with open(pat,‘ab‘) as f:                        flag = 1                        while flag:                            bt = conn.recv(1024)                            if len(bt) == 1 and bt == bytes(‘1‘,encoding=‘utf-8‘):                                flag = 0                            else:                                f.write(bt)                                file_size += len(bt)                                conn.sendall(bytes(str(file_size), encoding=‘utf-8‘))                        obj.netdisc.append(file_name)                        obj.download_beans += 50                else:                    conn.sendall(bytes(‘0‘,encoding=‘utf-8‘))                    file_size = 0                    with open(pat,‘wb‘) as f:                        flag = 1                        while flag:                            bt = conn.recv(1024)                            if len(bt) == 1 and bt == bytes(‘1‘, encoding=‘utf-8‘):                                flag = 0                            else:                                f.write(bt)                                file_size += len(bt)                                conn.sendall(bytes(str(file_size), encoding=‘utf-8‘))                        obj.netdisc.append(file_name)                        obj.download_beans += 50            elif choose == ‘2‘:                s = json.dumps(obj.netdisc)                conn.sendall(bytes(s, encoding=‘utf-8‘))                load_choose = str(conn.recv(1024),encoding=‘utf-8‘)                index_num = int(load_choose) - 1                download_file_name = obj.netdisc[index_num]                pat = os.path.join(Config.PATH,download_file_name)                all_size = os.stat(pat).st_size                print(type(all_size),all_size)                conn.sendall(bytes(str(all_size),encoding=‘utf-8‘))                if str(conn.recv(1024),encoding=‘utf-8‘) != ‘下载过‘:                    conn.sendall(bytes(‘知道‘,encoding=‘utf-8‘))                    seek_num = int(str(conn.recv(1024),encoding=‘utf-8‘))                    with open(pat,‘rb‘) as f:                        f.seek(seek_num)                        for line in f:                            conn.sendall(line)                        time.sleep(3)                        conn.sendall(bytes(‘0‘,encoding=‘utf-8‘))                else:                    conn.sendall(bytes(‘知道‘, encoding=‘utf-8‘))            elif choose == ‘3‘:                print(‘进入!‘)                s = json.dumps(Config.shared_file_list)                conn.sendall(bytes(s,encoding=‘utf-8‘))                print(‘已发出json格式信息‘)                #收到客户选择信息                choose = str(conn.recv(1024),encoding=‘utf-8‘)                index_num = int(choose) - 1                index_file_name = Config.shared_file_list[index_num]                print(index_file_name)                if obj.download_beans >= 20:                    obj.netdisc.append(index_file_name)                    obj.download_beans -= 20                    conn.sendall(bytes(‘添加成功‘,encoding=‘utf-8‘))                else:                    conn.sendall(bytes(‘下载豆不足!添加失败!‘,encoding=‘utf-8‘))            elif choose.lower() == ‘q‘:                with open(Config.ACCOUNT_INFO_PATH,‘rb‘) as f:                    li = pickle.loads(f.read())                    lis = []                    for i in li:                        if i.username == obj.username:                            lis.append(obj)                        else:                            lis.append(i)                with open(Config.ACCOUNT_INFO_PATH,‘wb‘) as f:                    f.write(pickle.dumps(lis))            elif choose == ‘4‘:                s = json.dumps(obj.netdisc)                conn.sendall(bytes(s,encoding=‘utf-8‘))if __name__ == ‘__main__‘:    server = socketserver.ThreadingTCPServer((‘127.0.0.1‘,8009),MyServer)    server.serve_forever()

   config.py

import osimport syspat = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))sys.path.append(pat)ACCOUNT_INFO_PATH = os.path.join(pat,‘db‘,‘用户信息.log‘)PATH = os.path.join(pat,‘db‘,‘共享文件‘)shared_file_list = os.listdir(PATH)

   account.py

import osimport syspat = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))sys.path.append(pat)from config import Configimport pickleimport hashlibclass Account:    def __init__(self):        self.username = None        self.password = None        self.download_beans = 0        self.netdisc = []    def registered(self,usr,pwd):        self.username = usr        self.password = pwd        self.download_beans = 50def usr_ver(usr):    ‘‘‘    注册时验证用户名存不存在    :param usr: 需要验证用户名    :return: 存在--返回用户名已存在,不存在--返回合法    ‘‘‘    if os.path.exists(Config.ACCOUNT_INFO_PATH):        with open(Config.ACCOUNT_INFO_PATH,‘rb‘) as f:            li = pickle.load(f)            for i in li:                if i.username == usr:                    return ‘用户名已存在!请重新输入!‘            return ‘合法‘    else:        return ‘合法‘def encrypt(pwd):    ‘‘‘    給密码加密的    :param pwd: 需要加密的密码    :return: 返回加密后的哈西值    ‘‘‘    m = hashlib.md5(bytes(‘明天更美好‘,encoding=‘utf-8‘))    m.update(bytes(pwd,encoding=‘utf-8‘))    return m.digest()def info_add(obj):    ‘‘‘    把注册好信息写入文件    :param obj: 注册的账户对象    :return:    ‘‘‘    if os.path.exists(Config.ACCOUNT_INFO_PATH):        with open(Config.ACCOUNT_INFO_PATH,‘rb‘) as f:            li = pickle.load(f)            li.append(obj)    else:        li = []        li.append(obj)    with open(Config.ACCOUNT_INFO_PATH, ‘wb‘) as f:        pickle.dump(li,f)def land_usr_ver(usr):    ‘‘‘    登录时验证用户名存不存在    :param usr: 需要验证用户名    :return: 存在--返回存在,不存在--返回你输入的用户名不存在    ‘‘‘    if os.path.exists(Config.ACCOUNT_INFO_PATH):        with open(Config.ACCOUNT_INFO_PATH,‘rb‘) as f:            li = pickle.load(f)            for i in li:                if i.username == usr:                    return ‘存在‘            return ‘输入的用户名不存在!请重新输入!‘    else:        return ‘输入的用户名不存在!请重新输入!‘def landed_ver(usr,pwd2):    ‘‘‘    用于用户名和密码验证    :param usr: 验证用户名    :param pwd: 验证密码    :return:    ‘‘‘    pwd = encrypt(pwd2)    li = pickle.load(open(Config.ACCOUNT_INFO_PATH,‘rb‘))    for i in li:        if i.username == usr and i.password == pwd:            return i    return ‘密码错误!请重新输入!‘

 

绝版FTP:猛戳这里

 

模拟百度云盘版的ftp