1. 程式人生 > >【小程序】支持多用戶在線的FTP程序

【小程序】支持多用戶在線的FTP程序

ive cmd png 傳輸過程 rmdir 創建 exc alt AR

功能:
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%\nfile 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(b200) #防粘包 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%\nreceive 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=%s\conf\\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(b200 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\navailable 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 = %s\conf\\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()

技術分享圖片

【小程序】支持多用戶在線的FTP程序