1. 程式人生 > >十八.Python模擬FTP檔案上傳

十八.Python模擬FTP檔案上傳

Python 模擬FTP斷點續傳併發伺服器

 

#配置檔案

#伺服器配置檔案

[server_config]
ip=127.0.0.1
port=8006
buffersize=1024
encoding=utf-8

#伺服器使用者資料 

[tom]
username=tom
password=123456
[alex]
username=alex
password=123456

 

#FTP伺服器程式碼

#程式入口
import optparse
import sys,os
#os.path.dirname 獲取檔案的資料夾路徑
path=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(path)
from core import main
class ftt_server:
   def __init__(self):
      self.option = optparse.OptionParser()
      self.option.add_option("-i", "--ip", dest="ip")
      self.option.add_option("-p", "--port", dest="port")
      self.opt, self.args = self.option.parse_args()
      self.one()
   def one(self):
      main.main(self.opt, self.args)

if __name__=="__main__":
   ftt_server()

#伺服器監聽程式
import socketserver
import optparse
import configparser
import os
from core import server
class main():
    def __init__(self,opt,args):
        args=args
        self.option=opt
        self.config=configparser.ConfigParser()
        self.config.read(os.path.dirname(os.path.dirname(__file__))+"/conf/config.ini")
        self.server=server
        self.BaseDir=os.path.dirname(os.path.dirname(__file__))
        self.validate(opt, args)
    def validate(self, options, args):
        cmd=args[0]
        if hasattr(self,cmd):
            fun=getattr(self,cmd)
            fun()
    def start(self):
        ip=self.option.ip
        port=self.option.port
        if ip=="":
            ip=self.getConfig("server_config","ip")
        if port=="":
            port=self.getConfig("server_config","port")
        print("server start Successful!")
        self.sock_ser=socketserver.ThreadingTCPServer((ip,int(port)),self.server.server_handler)
        self.sock_ser.serve_forever()

    def help(self):
        pass

    def getConfig(self,section,attribute):
        return self.config.read(section,attribute)


#伺服器主程式
import socketserver
import configparser
import os
import json
import sys
class server_handler(socketserver.BaseRequestHandler):
    def handle(self):
        self.config_name="server_config"
        self.BaseDir=os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
        self.config_Path=os.path.join(self.BaseDir,"conf","config.ini")
        self.user_config=os.path.join(self.BaseDir,"conf","user.ini")
        self.buffersize=int(self.getIni(self.config_Path,self.config_name,"buffersize"))
        self.encoding=self.getIni(self.config_Path,self.config_name,"encoding")
        self.currenSize=0
        data = self.request.recv(self.buffersize).decode(self.encoding)
        data = json.loads(data)
        print(data)
        fun = data["action"]
        if fun=="login":
            con=configparser.ConfigParser()
            con.read(self.user_config)
            if con.has_section(data["user"]):
                if con.get(data["user"],"password")==data["password"]:
                    self.currenDir=data["user"]
                    self.request.sendall("504".encode("utf-8"))
                    self.name=data["user"]
                    self.home=os.path.join(self.BaseDir, "home",data["user"])
                    self.currenDir=self.home
                    self.interception()
                else:
                    self.request.sendall("404".encode("utf-8"))
    

    def getIni(self,path,section,attribute):
        conf = configparser.ConfigParser()
        conf.read(path)
        return conf.get(section, attribute)
    #互動
    def interception(self):
        while 1:
            print("wait recv....")
            data=self.request.recv(self.buffersize)
            data=json.loads(data)
            print(data)
            fun=data["action"]
            if hasattr(self,fun):
                func=getattr(self,fun)
                func(**data)
            else:
                self.request.sendall("400".encode("utf-8"))
    #cd資料夾切換功能
    def cd(self,**kwargs):
        position=kwargs["position"]
        if position=="../":
            self.currenDir =os.path.dirname(self.currenDir)
        else:
            self.currenDir=os.path.join(self.currenDir,position)
        self.request.sendall(os.path.basename(self.currenDir).encode(self.encoding))
    #建立資料夾功能
    def mkdir(self,**kwargs):
        print(kwargs)
        position=kwargs["position"]
        mkfile=os.path.join(self.currenDir,position)
        try:
            if "/" in position or "\\" in position:
                os.makedirs(mkfile)
            else:
                os.mkdir(mkfile)
        except Exception as e:
            self.request.sendall("605".encode(self.encoding))
        self.request.sendall("606".encode(self.encoding))
    #顯示當前資料夾內容
    def ls(self,**kwargs):
        dir_con=os.listdir(self.currenDir)
        self.request.sendall(str(dir_con).encode("utf-8"))
    #檔案斷點續傳功能
    def put(self,**kwargs):
        file_name=kwargs["file_name"]
        file_size=kwargs["file_size"]
        target=kwargs["target"]
        self.target_file=os.path.join(self.currenDir,target,file_name)
        if os.path.exists(self.target_file):
            self.currenSize=os.stat(self.target_file).st_size
            if self.currenSize>=file_size:
                self.request.sendall("801".encode(self.encoding))
                return
            else:
                self.request.sendall("802".encode(self.encoding))
                data=self.request.recv(self.buffersize).decode(self.encoding)
                if data=="Y":
                    f = open(self.target_file, "ab")
                    self.request.sendall(str(self.currenSize).encode(self.encoding))
                else:
                    f = open(self.target_file, "wb")
        else:
            f = open(self.target_file, "wb")
            self.request.sendall("803".encode("utf-8"))

        while self.currenSize<file_size:
            data=self.request.recv(self.buffersize)
            f.write(data)
            self.currenSize+=len(data)
            self.progess(self.currenSize, file_size)
    #檔案上傳進度
    def progess(self,curren,total):
        rate = int(curren / total * 100)
        if rate > 0:
            st=sys.stdout
            st.write("%s%% %s \r\n"%(rate,"*"*rate))
            st.flush()
            if rate==100:
                print("upload finish!")


#FTP客戶端

#配置檔案

[client_config]
buffer_size=1024

#客戶端程式碼

#FTP客戶端程式
from socket import *
import sys,os
import optparse
import json
import configparser
path=os.path.dirname(os.path.dirname(__file__))
sys.path.append(path)

#狀態字典
dicts={"504":"登陸成功!",
      "404":"使用者或者密碼有誤!登陸失敗!",
      "400":"Input Error",
       "606":"create success",
       "605":"create fail",
       "801":"the file is existing",
       "802":"the file is existing,but not enough",
       "803":"the file start upload..."
      }

class client_handler:
    def __init__(self):
        self.option=optparse.OptionParser()
        self.option.add_option("-i", "--ip", dest="ip")
        self.option.add_option("-p", "--port", dest="port")
        self.option.add_option("-u", "--user", dest="username")
        self.option.add_option("-P", "--password", dest="password")
        self.conf = configparser.ConfigParser()
        self.Base_Dir=os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
        self.buffersize= int(self.bufferSize())
        self.size_file=0
        options, args = self.option.parse_args()
        self.task(options,args)
    def task(self, options, args):
        port=options.port
        if int(port)>0 and int(port)<65535:
            self.make_connection(options,args)
        else:
            exit("the port is in 0 and 65535!")
    def make_connection(self, options, args):
        self.sclient = socket(AF_INET, SOCK_STREAM)
        self.sclient.connect((options.ip, int(options.port)))
        self.login()
    def login(self):
        name=input("請輸入使用者名稱>>")
        password=input("請輸入密碼>>")
        self.json = {"action": "login", "user": name, "password": password}
        self.sclient.send(json.dumps(self.json).encode("utf-8"))
        data=self.sclient.recv(self.buffersize).decode("utf-8")
        # print(data)
        if data=="504":
            self.name=name
            print(dicts[data])
            while 1:
                code=input("[%s]"%self.name)
                cmd_list=code.split()
                if hasattr(self,cmd_list[0]):
                    fun=getattr(self,cmd_list[0])
                    fun(*cmd_list)
        else:
            print(dicts[data])
    def bufferSize(self):
        self.conf_path=os.path.join(self.Base_Dir,"conf","config.ini")
        self.conf.read(self.conf_path)
        return self.conf.get("client_config", "buffer_size")

    def put(self,*cmd_list):
        # print("put...")
        action,location,target=cmd_list
        file_name=os.path.basename(location)
        file_size=os.stat(location).st_size
        data={"action":action,
              "file_name":file_name,
              "file_size":file_size,
              "target":target}
        self.sclient.sendall(json.dumps(data).encode("utf-8"))
        data=self.sclient.recv(self.buffersize).decode("utf-8")
        self.parseNum(data)
        if data=="801":
            return
        elif data=="802":
            choice=input("the file is existing,but not enough,is continue?<Y/N>")
            if choice.upper()=="Y":
                self.sclient.sendall(choice.upper().encode("utf-8"))
                self.size_file =int(self.sclient.recv(self.buffersize).decode("utf-8"))
            else:
                self.sclient.sendall(choice.upper().encode("utf-8"))
        elif data=="803":
            pass
        f=open(location,"rb")
        f.seek(self.size_file)
        while self.size_file<file_size:
            fdata=f.read(self.buffersize)
            self.sclient.sendall(fdata)
            self.size_file+=len(fdata)
            self.progess(self.size_file, file_size)
    def cd(self,*cmd_list):
        # print("cd...")
        action,position=cmd_list
        data={"action":action,
              "position":position}
        data=json.dumps(data)
        self.sclient.sendall(data.encode("utf-8"))
        data=self.sclient.recv(self.buffersize).decode("utf-8")
        self.name=data
    def ls(self,*cmd_list):
        action=cmd_list[0]
        data={"action":action}
        data=json.dumps(data)
        self.sclient.sendall(data.encode("utf-8"))
        con=self.sclient.recv(self.buffersize).decode("utf-8")
        con=list(con)
        for i in con:
            print(i,end="\r")
    def mkdir(self,*cmd_list):
        print("mkdir...")
        action,position=cmd_list
        data={"action":action,
              "position":position
              }
        data=json.dumps(data)
        self.sclient.sendall(data.encode("utf-8"))
        con=self.sclient.recv(self.buffersize).decode("utf-8")
        print(dicts[con])
    def parseNum(self,st):
        print(dicts[st])
    def progess(self,curren,total):
        rate=int(curren/total*100)
        if rate > 0:
            st=sys.stdout
            st.write("%s%% %s\r\n"%(rate,"*"*rate))
            st.flush()
            if rate==100:
                print("upload finish!")

#程式入口
if __name__=="__main__":
    client_handler()








啟動

#伺服器啟動
python ftp_server start -i 127.0.0.1 -p 8006

#客戶端啟動
python ftp_client -i 127.0.0.1 -p 8006