zoukankan      html  css  js  c++  java
  • 【小程序】支持多用户在线的FTP程序

    功能:
    1.用户加密认证;

    2.允许同时多用户登陆;

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

    4.对用户进行磁盘配额,每个用户的可用空间不同;

    5.允许用户在ftp server上随意切换目录;

    6.允许用户查看当前目录上下文;

    7.允许用户上传和下载文件,保证文件的一致性

    8.文件传输过程中显示进度条;

    客户端:

    # Author:q1.ang
    
    import socket,os,json
    import hashlib
    import sys
    
    class FtpClient(object):
        def __init__(self):
            self.client = socket.socket()
            self.account=''
            self.path=''
    
        def help(self):
            '''
            帮助
            :return: none
            '''
            msg=
            '''help:
            dir
            cd ../..
            new ..
            del ..
            re ..
            put ..
            get ..'''
            print(msg)
    
        def connect(self,ip,port):
            '''
            连接
            :param ip:
            :param port:
            :return:
            '''
            self.client.connect((ip,port))
    
        def authenticate(self):
            '''
            用户登陆认证
            :return:auth真假
            '''
            auth=False
            try_count=0
            while try_count<3:
                self.account=input('Account:').strip()
                password=input('Password:').strip()
                #获取账号密码的MD5值
                m=hashlib.md5()
                m.update((self.account+password).encode('utf-8'))
                #发送acc+MD5
                self.client.send((self.account+' '+m.hexdigest()).encode('utf-8'))
                #接收服务器的认证结果
                auth_recv=json.loads(self.client.recv(1024).decode())
                print(auth_recv['log res'])
                if auth_recv['log res']=='login success':
                    auth=True
                    print('desk size:',auth_recv['desk size'])
                    return auth
                try_count+=1
                if try_count==3:
                    print('you have try 3 times...exit')
            else:
                return auth
    
        def interactive(self):
            '''
            交互模块,调用各个功能,在子功能中与服务器实现收发
            :return:none
            '''
            if self.authenticate(): #认证
                while True:
                    cmd = input('>>>').strip()
                    if len(cmd)==0:continue
                    cmd_str=cmd.split()[0]
                    if hasattr(self,'cmd_%s'%cmd_str):
                        func=getattr(self,'cmd_%s'%cmd_str)
                        func(cmd)
                    else:
                        self.help()
    
        def cmd_dir(self,*args):
            '''
            查看当面目录下文件
            :param args: dir没使用
            :return: none
            '''
            msg_dic = {
                'action':'dir'
            }
            self.client.send(json.dumps(msg_dic).encode('utf-8'))
            print(self.account,'list:')
            server_respone = self.client.recv(1024).decode()
            for i in json.loads(server_respone):
                print(i)
    
        def cmd_cd(self,*args):
            '''
            切换目录
            :param args: cd 目录名
            :return: none
            '''
            cmd_split=args[0].split()
            if len(cmd_split)>1:
                if cmd_split[1][0:len(self.account)]==self.account:
                    self.path = '\'+cmd_split[1][len(self.account)+1:]
                else:
                    self.path += '\'+cmd_split[1]
                msg_dic = {
                    'action': 'cd',
                    'path':self.path
                }
                print(msg_dic)
                self.client.send(json.dumps(msg_dic).encode('utf-8'))
                auth_path=self.client.recv(1024).decode()
    
                if  auth_path== 'True':
                    print((self.account+':'+self.path).replace('\\','\'))
                else:
                    print('找不到指定的路径')
            else:
                print('you not write the folder name...')
    
        def cmd_new(self,*args):
            '''
            新建目录
            :param args: cmd
            :return: new 目录名
            '''
            cmd_split=args[0].split()
            if len(cmd_split)>1:
                foldername=cmd_split[1]
                msg_dic={
                    'action':'new',
                    'foldername':foldername
                }
                self.client.send(json.dumps(msg_dic).encode('utf-8'))
                recv=self.client.recv(1024).decode()
                print(recv)
            else:
                print('no name of the new file...')
    
        def cmd_del(self,*args):
            '''
            删除目录或文件
            :param args:del 文件名
            :return: none
            '''
            cmd_split=args[0].split()
            if len(cmd_split)>1:
                msg_dic={
                    'action':'del',
                    'name':cmd_split[1]
                }
                self.client.send(json.dumps(msg_dic).encode('utf-8'))
                recv=self.client.recv(1024).decode()
                print(recv)
    
            else:
                print('no name of the file...')
    
        def cmd_re(self,*args):
            '''
            重命名
            :param args: re 文件名
            :return: none
            '''
            cmd_split=args[0].split()
            if len(cmd_split)>1:
                new_name=input('new name:').strip()
                msg_dic={
                    'action':'re',
                    'name':cmd_split[1],
                    'new name':new_name
                }
                self.client.send(json.dumps(msg_dic).encode('utf-8'))
                recv=self.client.recv(1024).decode()
                print(recv)
            else:
                print('the name of file or folder has not write..')
    
        def cmd_put(self,*args):
            '''
            上传文件
            :param args: put 文件名
            :return: none
            '''
            cmd_split=args[0].split()
            if len(cmd_split)>1:
                filename=cmd_split[1]
                if os.path.isfile(filename):
                    filesize=os.stat(filename).st_size
                    msg_dic = {
                        'action': 'put',
                        'filename': filename,
                        'filesize': filesize,
                        'override': True
                    }
                    self.client.send(json.dumps(msg_dic).encode('utf-8'))
    
                    server_respone=self.client.recv(1024).decode()
                    if server_respone=='out of memory':
                        print('the mamory of your desk is not enough to save this file[%s(%d Mb)]' % (filename, filesize / 1048576))
                    else:
                        l=0
                        sys.stdout.write('0%')
                        sys.stdout.flush()
                        with open(filename,'rb') as f:
                        # f=open(filename,'rb')
                            for line in f:
                                self.client.send(line)
                                l+=len(line)
                                if l>(filesize/20):
                                    sys.stdout.write('>')
                                    sys.stdout.flush()
                                    l-=(filesize/20)
                            else:
                                print('100%
    file upload success...')
                                save_sigle=self.client.recv(1024).decode()
                                print(save_sigle)
                else:
                    print(filename,'is not exit')
    
        def cmd_get(self,*args):
            '''
            下载文件
            :param args: get 文件名
            :return: none
            '''
            print('get')
            cmd_split=args[0].split()
            if len(cmd_split)>1:
                filename=cmd_split[1]
                msg_dic={
                    'action': 'get',
                    'filename':filename
                }
                self.client.send(json.dumps(msg_dic).encode('utf-8'))
                auth_recv=json.loads(self.client.recv(1024).decode())
                if auth_recv['file acc']=='file exist':
                    filesize=auth_recv['filesize']
                    revc_size=0
                    l=0
                    sys.stdout.write('0%')
                    sys.stdout.flush()
                    self.client.send(b'200')    #防粘包
                    if os.path.isfile(filename):
                        filename=filename+'.new'
                    with open(filename,'wb')as f:
                        while revc_size<filesize:
                            recv=self.client.recv(1024)
                            f.write(recv)
                            revc_size+=len(recv)
                            l+=len(recv)
                            if l>(filesize/20):
                                sys.stdout.write('>')
                                sys.stdout.flush()
                                l-=(filesize/20)
                        else:
                            print('100%
    receive done')
                else:
                    print(auth_recv['file acc'])
            else:
                print('error:not write filename...')
    
    ftp=FtpClient()
    ftp.connect('localhost',6666)
    ftp.interactive()

    服务器端:

    # Author:q1.ang
    import socketserver,json,os
    import hashlib
    
    class MyTCPHandler(socketserver.BaseRequestHandler):
        acc_path = ''
        account =''
        available_size=0
        data_dic={}
        def authenticate(self):
            '''
            用户认证
            :return: auth真假
            '''
            auth=False
            try_count = 0
            while try_count < 3:
                #接收客户端的账号密码
                account,recv_md5=self.request.recv(1024).decode().split()
                print(account,recv_md5)
                BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
                file_path='%sconf\accounts\%s'%(BASE_DIR,account)
                if os.path.isfile(file_path):
                    with open(file_path,'r') as f:
                        # acc_data=json.load(f)
                        self.data_dic=json.load(f)
                        m=hashlib.md5()
                        m.update((self.data_dic['account']+self.data_dic['password']).encode('utf-8'))
                        print(m.hexdigest())
                        if m.hexdigest()==recv_md5:
                            print('login success')
                            self.account=account
                            used_size = int(self.data_dic['desk size'].split('/')[0])
                            all_size = int(self.data_dic['desk size'].split('/')[1])
                            self.available_size = all_size - used_size
    
                            print('available_size',self.available_size)
    
                            msg_dic = {
                                'log res': 'login success',
                                'desk size': '%dMb/%dMb'%(used_size/1048576,all_size/1048576)
                            }
                            auth=True
                            try_count=3
                        else:
                            print('account or password error')
                            msg_dic={
                                'log res':'account or password error',
                            }
                else:
                    print('the account dose not exist..')
                    msg_dic = {
                        'log res': 'the account dose not exist..',
                    }
                try_count+=1
                self.request.send(json.dumps(msg_dic).encode('utf-8'))
    
            return auth
    
        def cmd_dir(self,*args):
            '''
            查看目录下文件
            :param args: cmd_dic
            :return: none
            '''
            print(self.acc_path)
            print(os.listdir(self.acc_path))
            self.request.send(json.dumps(os.listdir(self.acc_path)).encode('utf-8'))
    
        def cmd_cd(self,*args):
            '''
            切换目录
            :param args: cmd_dic
            :return: none
            '''
            BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            self.acc_path = '%s\conf\data\%s'%(BASE_DIR,self.account)
            auth_path='False_path' #不能发空字节
            path=self.acc_path+args[0]['path']
            print('地址:',path)
            if os.path.exists(path):
                self.acc_path=path
                auth_path='True'
                print('path',self.acc_path)
            else:
                print('找不到指定的路径')
            self.request.send(auth_path.encode('utf-8'))
    
        def cmd_new(self,*args):
            '''
            在当前目录下新建目录
            :param args: cmd_dic
            :return: none
            '''
            path=self.acc_path+'\'+args[0]['foldername']
            if os.path.exists(path):
                print('folder is exist..')
                msg='folder is exist..'
            else:
                os.mkdir(path)
                print('创建成功')
                msg = 'folder create success..'
            self.request.send(msg.encode('utf-8'))
    
        def cmd_re(self,*args):
            '''
            在当前目录下重命名文件
            :param args: cmd_dic
            :return: none
            '''
            name = self.acc_path + '\' + args[0]['name']
            new_name=self.acc_path + '\' + args[0]['new name']
            try:
                os.rename(name,new_name)
                msg='rename success'
            except FileNotFoundError as e:
                msg='the folder is not exist...'
                print(e)
            self.request.send(msg.encode('utf-8'))
    
        def cmd_del(self,*args):
            '''
            在当前目录下删除目录(空)或文件
            :param args: cmd_dic
            :return: none
            '''
            path = self.acc_path + '\' + args[0]['name']
            if os.path.isfile(path):
                os.remove(path)
                msg='del success'
            elif os.path.exists(path):
                try:
                    os.rmdir(path)
                    msg = 'del success'
                except OSError as e:
                    print(e)
                    msg='the folder is not empty...'
            else:
                msg='file or folder is not exist...'
            self.request.send(msg.encode('utf-8'))
    
        def cmd_put(self,*args):
            '''
            接收客户端文件
            :return:
            '''
            cmd_dic=args[0]
            filename=cmd_dic['filename']
            filesize=cmd_dic['filesize']
    
            if filesize>self.available_size:
                self.request.send('out of memory'.encode('utf-8'))
            else:
                file_path='%s\%s'%(self.acc_path,filename)
                if os.path.isfile(file_path):
                    f=open(file_path+'.new','wb')
                else:
                    f = open(file_path, 'wb')
                self.request.send(b'200 ok') #防粘包
                recv_size=0
                while recv_size< filesize:
                    data=self.request.recv(1024)
                    f.write(data)
                    recv_size+=len(data)
                else:
                    f.close()
                    print('file [%s] has uploaded'%filename)
                    self.available_size -= filesize
                    print('available_size2',self.available_size)
                    self.request.send(('server save success
    available size:'
                                       '%d Mb'%(self.available_size/1048576)).encode('utf-8'))
                    #更新用户数据
                    used_size=self.data_dic['desk size'].split('/')[0]
                    all_size=self.data_dic['desk size'].split('/')[1]
                    print('filesize',filesize)
                    print('used_size',used_size)
                    print('all_size',all_size)
                    self.data_dic['desk size']='%d/%s'%(int(used_size)+filesize,all_size)
    
                    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
                    file_path = '%sconf\accounts\%s' % (BASE_DIR, self.account)
                    print(file_path)
                    with open(file_path,'w') as f:
                        json.dump(self.data_dic,f)
    
        def cmd_get(self,*args):
            '''
            发送给客户端文件
            :param args: cmd_dic
            :return: none
            '''
            cmd_dic=args[0]
            filename=cmd_dic['filename']
            file_path='%s\%s'%(self.acc_path,filename)
            if os.path.isfile(file_path):
                filesize=os.stat(file_path).st_size
                msg_dic={
                    'file acc':'file exist',
                    'filesize':filesize
                }
                self.request.send(json.dumps(msg_dic).encode('utf-8'))
                self.request.recv(1024) #防粘包
                with open(file_path,'rb')as f:
                    for line in f:
                        self.request.send(line)
                    else:
                        print('file send done')
    
            else:
                msg_dic = {'file acc': 'file[%s] is not exist...'%filename}
                self.request.send(json.loads(msg_dic).encode('utf-8'))
    
        def handle(self):
            '''
            重构socketserver的handle(),用来主要的交互
            :return: 
            '''
            print('waiting...')
            if self.authenticate():
                BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
                self.acc_path = '%s\conf\data\%s' % (BASE_DIR, self.account)
                while True:
                    print('登录成功',self.account)
                    try:
                        self.data=self.request.recv(1024).strip()
                        print('{} wrote'.format(self.client_address[0]))
                        cmd_dic=json.loads(self.data.decode())
                        print(cmd_dic)
                        action='cmd_'+cmd_dic['action']
                        if hasattr(self,action):
                            func=getattr(self,action)
                            func(cmd_dic)
    
                    except ConnectionResetError as e:
                        print('ConnectionResetError',e)
                        break
    
    if __name__=='__main__':
        HOST,PORT='localhost',6666
        server=socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)
        server.serve_forever()

     

  • 相关阅读:
    rgba 和opacity的透明效果有什么不同
    定位 盒模型 浮动 css优先级 伪类伪元素选择器---未完成
    JS中Date对象getYear()方法和getFullYear()方法区别
    Javascript错误提示--SyntaxError: Illegal return statement
    JavaScript高级程序设计-第六章面向对象的程序设计(复习)
    为什么js加事件时不要写括号
    JS函数是如何执行的
    关于JS的总结
    我所知道的数据库6-DDL语言(续)
    我所知道的数据库5-DDL语言
  • 原文地址:https://www.cnblogs.com/q1ang/p/9193232.html
Copyright © 2011-2022 走看看