python3自学之路作业 开发一个支持多用户在线的FTP程序

 

作业要求:
  1. 用户加密认证
  2. 允许同时多用户登录
  3. 每个用户有自己的家目录 ,且只能访问自己的家目录
  4. 对用户进行磁盘配额,每个用户的可用空间不同
  5. 允许用户在ftp server上随意切换目录
  6. 允许用户查看当前目录下文件
  7. 允许上传和下载文件,保证文件一致性
  8. 文件传输过程中显示进度条
  9. 附加功能:支持文件的断点续传

 

 

未实现的功能:
    磁盘配额、上传或下载时自动创建目录、断点续传

 

 

 

缺点:
    1、没有对异常操作进行处理(比如 命令异常 文件不存在 路径不存在)
吐槽框:
     脑子不够使,花了3天左右才做成这样子,惭愧,但是在不想做了,想接着往下学
 
改进思路:

 

 

    1、磁盘配额:可以根据用户目录下文件的总大小
    2、命令异常:对每一次的命令进行检测 不符合要求的 直接break或continue

 

 

 

    3、文件夹不存在:自动创建
    4、文件不存在:返回异常信息

 

程序结构:
main.py
 
'''
Created on 2018年5月28日

@author: hcl
'''
import os,sys

file_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  
core_path = file_path + r'\core'  
sys.path.append(file_path) 

from core import ftp_server
from core import account_operation


if __name__ == "__main__":
    
    server_start = ftp_server.Ftpserver_start()
    server_start.start()

account_operation.py

'''
Created on 2018年5月28日

@author: hcl
'''

import os,pickle,hashlib,socket
from core import file_operation

file_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  
db_path = file_path + r'\db'  


class Save_account(object):
    """
    storing the account message , 
    and the password was encrypted by hashlib.md5
    """
    def __init__(self,account,password): 
        m = hashlib.md5()      
        self.account = account
        m.update(password.encode('utf-8'))
        self.password = m.hexdigest()
        
    def save_msg(self):
        print(type(self.account))
        filepath = db_path + '\\' + self.account  
        if not os.path.isdir(db_path):
            os.mkdir(db_path)
            print("make a new dir %s successful." %db_path)
        else:
            info = {}
            info['account'] = self.account
            info['password'] = self.password
            with open(filepath,'wb') as f:
                f.write(pickle.dumps(info))
                f.flush()
                print('----------save a new account successful----------')

            
class Check_account(object):
    """
    check the account message , 
    """
    def __init__(self):
        self.account = ''
        pass
    
    def check_msg(self,account,password):
        
#         account = input("Please input your account:").strip()  
#         password = input("Please input your password::").strip()     
        m = hashlib.md5()
        filepath = db_path + '\\' + account
        print(filepath)
        if os.path.isfile(filepath):
            with open(filepath,'rb') as f:
                file_dict = pickle.load(f)
                m.update(password.encode('utf-8'))                
                if file_dict['account'] == account and  file_dict['password'] == m.hexdigest():
                    self.account = account
                    print("check correct")
                    return True
                else:
                    print("invalid password")
                    return False
                    
        else:
            print("invalid account")
            return False

if __name__ == "__main__":
    c1 = Check_account()
    print(c1.check_msg('ln','ln'))
# 
#     s1 = Save_account("ln","ln")  
#     s1.save_msg()
    
#     c1 = Check_account()
#     tf = c1.check_msg()
#     if tf:
#         path = file_operation.Account_homepage(c1.account)
#         print(path.ls())
#         path.addpath('hecanlong')
#         path.cd('../')
#  
#          
#     else:
#         print("wrong account")

file_operation.py

'''
Created on 2018年5月28日

@author: hcl
'''
import hashlib,os,socket

class Upfile(object):
    """
        Upfile(filename)
    """
    def __init__(self):
        pass
    
    def up(self,*args):
        
        #print('up:',args )
        print("***********Up Start***********")
        if os.path.isfile(args[0]):  
            f = open(args[0],'rb')  
            m = hashlib.md5()  
            filesize = os.stat(args[0]).st_size  
            print('up filesize:',filesize)
            
            if args[1] == 'client':
                print('up from client')
                ack = self.recv(1024)
                self.send(str(filesize).encode(encoding='utf-8'))
            else:
                print('up from server')
                ack = self.request.recv(1024)
                self.request.sendall(str(filesize).encode(encoding='utf-8'))    
            #ack = self.recv(1024)
            #self.send(str(filesize).encode(encoding='utf-8'))                     
            for line in f:  
                m.update(line)#.encode(encoding='utf-8')  
                if args[1] == 'client':
                    self.send(line)#.encode(encoding='utf-8') 
                else:
                    self.request.sendall(line)
                #self.send(line)#.encode(encoding='utf-8')  
            print('up file md5:',m.hexdigest())
              
            f.close() 
            if args[1] == 'client':
                self.send(m.hexdigest().encode(encoding='utf-8'))# 
            else:
                self.request.sendall(m.hexdigest().encode(encoding='utf-8'))
            #self.send(m.hexdigest().encode(encoding='utf-8'))#  
            
            print("***********Up Done***********")

class DownLoadfile(object):
    """
        DownLoadfile(filepath)
    """
    def __init__(self):
        pass

    def down(self,*args):
        print("***********Down Start***********")
        print('down:',args )
        if args[1] == 'client':
            self.send(b'ok')# 
            file_total_size = int(self.recv(1024).strip().decode())
        else:
            self.request.sendall(b'ok') # give a response to client
            file_total_size = int(self.request.recv(1024).strip().decode())
        #self.request.sendall(b'ok') # give a response to client
        #file_total_size = int(self.request.recv(1024).strip().decode())
        
        print('down file_total_size:',file_total_size)
        recv_size = 0  
        filename = args[0]#[0][1]
        print('filename:',filename)  
        f = open(filename + 'new','wb')  
        m = hashlib.md5()   
        pbar = Progressbar()             
        while recv_size != file_total_size:  
            if file_total_size - recv_size > 1024:  
                size = 1024  
            else:  
                size = file_total_size - recv_size  
                #print('last recv_size:',recv_size)
            if args[1] == 'client':
                data = self.recv(size) 
            else:
                data = self.request.recv(size) 
            #data = self.request.recv(size) 
            
            recv_size += len(data)  
            m.update(data)  
            f.write(data)  
            f.flush()  
            #print('recv_size:',recv_size,'file_total_size:',file_total_size)  
            print("Processing:%.2f%%"  %(pbar.progressing(recv_size, file_total_size)))
        else:  
            new_file_md5 = m.hexdigest()
            if args[1] == 'client':
                server_datamd5 = self.recv(1024).decode()
            else:
                server_datamd5 = self.request.recv(1024).decode()
            #server_datamd5 = self.request.recv(1024).decode()  
            print("file recv done",recv_size,file_total_size)  
            print("down_md5:",new_file_md5)  
            print('up_md5:',server_datamd5)
        print("***********Down Done***********")
           
class Progressbar(object):
    def __init__(self):
        pass
    
    def progressing(self,temp,total):
        return temp/total*100
                
class Discretetrainsport(object):
    """
        Discretetrainsport(filepath,continue_point)
    """
    def __init__(self):
        pass    
    def discrete(self,*args):
        print(*args)
        
class Account_homepage(object):
    def __init__(self,file):
        self.file_path = file
        
    def getrealpath(self):
        rp = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '\\home\\' + self.file_path
        return rp
    
    def addpath(self,file):
        self.file_path = self.file_path + '\\' + file
        return self.file_path
    
    def decpath(self):
        path_list = self.file_path.split('\\')
        self.file_path = '\\'.join(path_list[0:-1])
        return self.file_path
    
    #def ls(self,send):
    def ls(self):
        print(os.listdir(self.getrealpath()))
        #send.request.sendall(str(os.listdir(self.getrealpath())).encode(encoding='utf-8'))
        return os.listdir(self.getrealpath())

    def cd(self,*args):
        base_path = self.getrealpath() + "\\"
        path_len = len(self.file_path.split('\\'))

        if not args[0] == "../":
            if os.path.isdir(base_path+args[0]):           
                self.file_path = self.addpath(args[0])
                print("new path:",self.file_path)
                return self.file_path
            else:
                print(" ********* ",args[0]," doesn't exist.."," ********* ") 
                return (" ********* ",args[0]," doesn't exist.."," ********* ")  
                #return False
        elif args[0] == "../" and path_len > 1:
            self.file_path = self.decpath()
            print("new path:",self.file_path)
            return self.file_path
        else:
            print(" ********* You have got into the bottom ********* ")   
            return(" ********* You have got into the bottom ********* ")
            #return False
    def creat(self,*args):
        pass
    
if __name__ == "__main__":
    a1 = Account_homepage("hcl\home\ln")
    a1.addpath('1234')
    a1.decpath()


ftp_client.py

'''
Created on 2018年5月28日

@author: hcl
'''
import socket
from core import file_operation
from core import account_operation

client = socket.socket()    

HOST,PORT = "localhost",50000 

class Ftpclient_start(object):
    
    def __init__(self):
        pass

    def start(self):
        
        client.connect((HOST,PORT))  
        print(Clientcheck.check(client))

        while True:
            try:  
                msg = input(">>>:") 
            except:
                break
            else: 
                client.send(msg.encode())  # send cmd to the server  
                
                if msg.startswith('up'): # "up data.txt"
                    file_operation.Upfile.up(client,msg.split()[1],'client')
                    
                elif msg.startswith('download'):
                    file_operation.DownLoadfile.down(client,msg.split()[1],'client')  
                    
                elif msg.startswith('ls'):
                    print('*****************ls start*****************')
                    rec_info = client.recv(1024).strip().decode()
                    print(rec_info)
                    print('*****************ls end*****************')
                    
                else:
                    print('*****************cd start*****************')
                    rec_info = client.recv(1024).strip().decode()
                    print(rec_info)
                    print('*****************cd end*****************')
                    
class Clientcheck(object):
    def __init__(self):
        pass
    
    def check(self):
        account = input("Please input your account:").strip()  
        password = input("Please input your password:").strip() 
        
        #info = [account,password]
        info = account + ' ' +password
        
        self.send(str(info).encode('utf-8'))
        rec_info = self.recv(1024).strip().decode()
        print(rec_info)               
        return rec_info
                    
if __name__ == "__main__":

    client_start = Ftpclient_start()
    client_start.start()

ftp_server.py

'''
Created on 2018年5月28日

@author: hcl
'''
import socketserver
from core import file_operation
from core import account_operation

HOST,PORT = "localhost",50000 
  
class MyTCPHandler(socketserver.BaseRequestHandler):    
    def handle(self): 
        op = {
        "cd":file_operation.Account_homepage.cd,
        "ls":file_operation.Account_homepage.ls,
        "up":file_operation.DownLoadfile.down,
        "download":file_operation.Upfile.up,
        "check":account_operation.Check_account.check_msg
        } 
        
        account_name = Servercheck.check(self)
        login_account = file_operation.Account_homepage(account_name)
        
        print("login account:",account_name)
        while True:  
            try:
                self.data = self.request.recv(1024).strip()  # analysize the cmd data from client
                if not self.data:
                    continue
                cmd_data = self.data.decode()
                cmd_dict = cmd_data.split()
                #if len(cmd_dict) > 1:
                if  cmd_dict[0] == 'up' or cmd_dict[0] == 'download':
                    op[cmd_dict[0]](self,cmd_dict[1],'server')
                    
                elif cmd_dict[0] == 'cd':
                    #op[cmd_dict[0]](login_account,cmd_dict[1])
                    self.request.sendall(str(op[cmd_dict[0]](login_account,cmd_dict[1])).encode(encoding='utf-8'))
                    
                else:     #ls
                    #op[cmd_dict[0]](login_account,self)
                    self.request.sendall(str(op[cmd_dict[0]](login_account)).encode(encoding='utf-8'))
                    
            except ConnectionResetError as e:  
                print("MyTCPHandler handle err:", e)  
                break  

class Ftpserver_start(object):
    def __init__(self):
        pass
    
    def start(self):
        print('socketserver start.....')
        server = socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)  
        server.serve_forever()

class Servercheck(object):
    def __init__(self):
        pass
    
    def check(self):
        info = []
        info = self.request.recv(1024).strip().decode().split()
        print("server recv info:",info[0],info[1])
        
        c1 = account_operation.Check_account()
        acc = c1.check_msg(info[0],info[1])
        
        self.request.sendall(str(acc).encode(encoding='utf-8'))
        return info[0]
        
           

 

程序运行 启动main.py  ftp_client.py
客户端1操作:
Please input your account:hcl
Please input your password:hcl
True
True
>>>:ls
*****************ls start*****************
['123', '213.txt', 'asdjk.txt']
*****************ls end*****************
>>>:cd 123
*****************cd start*****************
hcl\123
*****************cd end*****************
>>>:ls
*****************ls start*****************
[]
*****************ls end*****************
>>>:cd ../
*****************cd start*****************
hcl
*****************cd end*****************
>>>:ls
*****************ls start*****************
['123', '213.txt', 'asdjk.txt']
*****************ls end*****************
>>>:up data.txt
***********Up Start***********
up filesize: 938
up from client
up file md5: e7f3675df6fa4058b86bb9d7d8004eb5
***********Up Done***********
>>>:download 123.txt
***********Down Start***********
down: ('123.txt', 'client')
down file_total_size: 938
filename: 123.txt
Processing:73.56%
Processing:89.87%
Processing:95.95%
Processing:100.00%
file recv done 938 938
down_md5: e7f3675df6fa4058b86bb9d7d8004eb5
up_md5: e7f3675df6fa4058b86bb9d7d8004eb5
***********Down Done***********
>>>:
 

客户端2操作:

Please input your account:ln
Please input your password:ln
True
True
>>>:up data.txt
***********Up Start***********
up filesize: 938
up from client
up file md5: e7f3675df6fa4058b86bb9d7d8004eb5
***********Up Done***********
>>>:download 123.txt
***********Down Start***********
down: ('123.txt', 'client')
down file_total_size: 938
filename: 123.txt
Processing:68.02%
Processing:82.62%
Processing:86.89%
Processing:87.10%
Processing:89.87%
Processing:90.09%
Processing:95.95%
Processing:100.00%
file recv done 938 938
down_md5: e7f3675df6fa4058b86bb9d7d8004eb5
up_md5: e7f3675df6fa4058b86bb9d7d8004eb5
***********Down Done***********
>>>:

服务器输出:

socketserver start.....
server recv info: hcl hcl
D:\F\eclipse-workspace\ftp\src\db\hcl
check correct
login account: hcl
['123', '213.txt', 'asdjk.txt']
new path: hcl\123
[]
new path: hcl
['123', '213.txt', 'asdjk.txt']
***********Down Start***********
down: ('data.txt', 'server')
down file_total_size: 938
filename: data.txt
Processing:60.77%
Processing:86.89%
Processing:87.10%
Processing:90.09%
Processing:95.95%
Processing:100.00%
file recv done 938 938
down_md5: e7f3675df6fa4058b86bb9d7d8004eb5
up_md5: e7f3675df6fa4058b86bb9d7d8004eb5
***********Down Done***********
***********Up Start***********
up filesize: 938
up from server
up file md5: e7f3675df6fa4058b86bb9d7d8004eb5
***********Up Done***********
server recv info: ln ln
D:\F\eclipse-workspace\ftp\src\db\ln
check correct
login account: ln
***********Down Start***********
down: ('data.txt', 'server')
down file_total_size: 938
filename: data.txt
Processing:68.02%
Processing:82.62%
Processing:87.10%
Processing:89.87%
Processing:90.09%
Processing:95.95%
Processing:100.00%
file recv done 938 938
down_md5: e7f3675df6fa4058b86bb9d7d8004eb5
up_md5: e7f3675df6fa4058b86bb9d7d8004eb5
***********Down Done***********
***********Up Start***********
up filesize: 938
up from server
up file md5: e7f3675df6fa4058b86bb9d7d8004eb5
***********Up Done***********

六、有兴趣接电子设计相关小型项目的请加下群,每个项目一般在1000元以内,非诚勿扰

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值