溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

python如何實(shí)現(xiàn)簡(jiǎn)單的FTP程序

發(fā)布時(shí)間:2021-04-26 11:17:29 來(lái)源:億速云 閱讀:165 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹了python如何實(shí)現(xiàn)簡(jiǎn)單的FTP程序,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

Python的優(yōu)點(diǎn)有哪些

1、簡(jiǎn)單易用,與C/C++、Java、C# 等傳統(tǒng)語(yǔ)言相比,Python對(duì)代碼格式的要求沒(méi)有那么嚴(yán)格;2、Python屬于開(kāi)源的,所有人都可以看到源代碼,并且可以被移植在許多平臺(tái)上使用;3、Python面向?qū)ο螅軌蛑С置嫦蜻^(guò)程編程,也支持面向?qū)ο缶幊蹋?、Python是一種解釋性語(yǔ)言,Python寫(xiě)的程序不需要編譯成二進(jìn)制代碼,可以直接從源代碼運(yùn)行程序;5、Python功能強(qiáng)大,擁有的模塊眾多,基本能夠?qū)崿F(xiàn)所有的常見(jiàn)功能。

FTP即文件傳輸協(xié)議;它基于客戶(hù)機(jī)-服務(wù)器模型體系結(jié)構(gòu),應(yīng)用廣泛。它有兩個(gè)通道:一個(gè)命令通道和一個(gè)數(shù)據(jù)通道。命令通道用于控制通信,數(shù)據(jù)通道用于文件的實(shí)際傳輸。使用FTP可以做很多事情,比如移動(dòng)、下載、復(fù)制文件等。

一、開(kāi)發(fā)環(huán)境

server端:centos 7  python-3.6.2

客戶(hù)端:Windows 7 python-3.6.2 pycharm-2018

程序目的:1、學(xué)習(xí)使用socketserver實(shí)現(xiàn)并發(fā)處理多個(gè)客戶(hù)端。

             2、了解使用struct解決TCP粘包。

二、程序設(shè)計(jì)

(本人菜鳥(niǎo)一枚,對(duì)于開(kāi)發(fā)規(guī)范,接口設(shè)計(jì)完全不懂,完全是隨心所欲,自?shī)首詷?lè)。寫(xiě)博客主要是記錄自己學(xué)習(xí)的點(diǎn)點(diǎn)滴滴,如有不足之處還請(qǐng)見(jiàn)諒。)

1、server端

1.1 目錄結(jié)構(gòu)如下:

python如何實(shí)現(xiàn)簡(jiǎn)單的FTP程序

 1.2 目錄簡(jiǎn)介:

FTP_SERVER:程序主目錄

app:程序主邏輯目錄,目錄下有四個(gè)模塊:

          FTPserver.py:FTP  Server端啟動(dòng)入口。

          login.py:認(rèn)證注冊(cè)模塊,用于處理用戶(hù)注冊(cè),登錄認(rèn)證。

          dataAnalysis.py:命令解析模塊,負(fù)責(zé)解析,執(zhí)行客戶(hù)端命令。

          FileOpertion.py:負(fù)責(zé)文件讀,寫(xiě)。數(shù)據(jù)發(fā)送,數(shù)據(jù)接收。

db:存放user_pwd.db文件,用于存放用戶(hù)信息(用戶(hù)名,密碼,F(xiàn)TP目錄總空間,已使用空間等)

lib:存放公共數(shù)據(jù)。

1.3 模塊中類(lèi)的繼承關(guān)系

python如何實(shí)現(xiàn)簡(jiǎn)單的FTP程序

1.4 執(zhí)行流程

1.4.1 程序啟動(dòng)文件FTPserver.py,程序啟動(dòng)后進(jìn)入監(jiān)聽(tīng)狀態(tài)。核心代碼如下:

class MyFtpServer(socketserver.BaseRequestHandler):
 
 def handle(self): # 重寫(xiě)handle方法,處理socket請(qǐng)求
 print(f"連接來(lái)自{self.client_address}的客戶(hù)端")
 commom_obj = Commom()
 data_analy = DataAnalysis()
 login_obj = Login()
 while 1:
 # 執(zhí)行用戶(hù)選項(xiàng):1、登陸系統(tǒng) 2、注冊(cè)賬號(hào)。并返回一個(gè)結(jié)果
 status_id = login_obj.run_client_choice(self.request, commom_obj)
 if status_id == "01": # 登陸成功
 if not self.run_ftp_server(data_analy,commom_obj): # 執(zhí)行ftpserver主功能
  break
 elif int(status_id) == -1: # client斷開(kāi)連接了
 break
 print(f"客戶(hù)端{(lán)self.client_address}斷開(kāi)了連接")

 def run_ftp_server(self,data_analy,commom_obj):
 """"
 登陸成功后,接收客戶(hù)端發(fā)來(lái)的命令,并進(jìn)行處理
 :param data_analy:負(fù)責(zé)解析,執(zhí)行客戶(hù)端命令的對(duì)象
 :param commom_obj:程序執(zhí)行時(shí)所需的數(shù)據(jù)對(duì)象
 :return 返回false代表客戶(hù)端斷開(kāi)連接了
 """
 while True:
 try:
 cmd_len_pack = self.request.recv(4) 
 cmd_len = struct.unpack('i',cmd_len_pack)[0] # 獲取命令長(zhǎng)度,防止粘包 
 except Exception:
 break
 recv_data = self.request.recv(cmd_len).decode('utf-8') # 接收客戶(hù)端數(shù)據(jù)
 if recv_data.upper() == "Q": # 客戶(hù)端提出斷開(kāi)連接了
 break
 # 解析,處理客戶(hù)端的命令
 data_analy.syntax_analysis(recv_data, self.request, commom_obj)
 return False
if __name__ == '__main__':
 print('運(yùn)行FTP服務(wù)')
 ip_port = ('192.168.10.10',9000)
 # 創(chuàng)建并發(fā)服務(wù)端對(duì)象
 server = socketserver.ThreadingTCPServer(ip_port, MyFtpServer)
 # 開(kāi)啟服務(wù)
 server.serve_forever()

 1.4.2 服務(wù)端進(jìn)入監(jiān)聽(tīng)狀態(tài)后,客戶(hù)端發(fā)起連接請(qǐng)求,服務(wù)端接收連接請(qǐng)求后會(huì)等待客戶(hù)單發(fā)來(lái)狀態(tài)碼,1表示請(qǐng)求登錄FTP服務(wù)器,2表示客戶(hù)端要注冊(cè)用戶(hù),注冊(cè)用戶(hù)需要服務(wù)端手動(dòng)反饋狀態(tài)碼1才可注冊(cè)。處理用戶(hù)登錄,注冊(cè)模塊login.py核心代碼如下:

class Login(FileOperation):
 """
 登陸注冊(cè)類(lèi)。主要負(fù)責(zé)用戶(hù)的登陸認(rèn)證,和用戶(hù)注冊(cè)。
 """
 def run_client_choice(self,socket_obj,commom):
 """
 獲取客戶(hù)端的請(qǐng)求,1是登陸,2是注冊(cè)用戶(hù)
 :param socket_obj: socket對(duì)象
 :param commom: ftpserver運(yùn)行時(shí)所需要的數(shù)據(jù)對(duì)象
 :return:
 """
 recv_choice = socket_obj.recv(1).decode("utf-8") # 獲取用戶(hù)選項(xiàng):1是登陸,2是注冊(cè)用戶(hù)
 if recv_choice == "1": # client請(qǐng)求登陸
 return self.login_authen(socket_obj,commom)
 elif recv_choice == "2": # client請(qǐng)求注冊(cè)賬號(hào)
 return self.register_user(socket_obj,commom)
 else:
 return -1 # client斷開(kāi)連接了
 # 用戶(hù)登陸認(rèn)證
 def login_authen(self,socket_obj,commom):
 """
 客戶(hù)端登陸認(rèn)證
 :param socket_obj: socket對(duì)象
 :param commom: ftpserver運(yùn)行時(shí)需要的數(shù)據(jù)對(duì)象
 :return:返回1代表登陸成功
 """
 # 接收client發(fā)來(lái)的用戶(hù)名,密碼
 recv_userPwd = self.recv_data(socket_obj).decode("utf-8").split("|") 
 # 效驗(yàn)用戶(hù)名密碼
 check_ret = self.check_user_pwd(recv_userPwd, socket_obj,commom)
 if check_ret: # 用戶(hù)名密碼正確
 self.check_user_home_dir(commom,recv_userPwd[0]) # 檢測(cè)用戶(hù)家目錄
 return commom.status_info["login_success"]
 else:
 return commom.status_info["login_fail"]
 ...
 # 注冊(cè)用戶(hù)
 def register_user(self,socket_obj,commom):
 """
 :param socket_obj:
 :param commom:
 :return: 返回是否允許注冊(cè)的結(jié)果,1允許客戶(hù)端注冊(cè),2拒絕客戶(hù)端注冊(cè)
 """
 while True:
 choice_id = input("請(qǐng)輸入回應(yīng)碼:1是允許注冊(cè),2是不允許注冊(cè):")
 if choice_id.isdigit() and 3 > int(choice_id) > 0:
 socket_obj.send(choice_id.encode("utf-8")) # 發(fā)通知告知客戶(hù)端,處理結(jié)果
 if choice_id == "1": # 注冊(cè)用戶(hù)
  return self.client_register(socket_obj, commom)
 return choice_id
 else:
 print("您輸入的信息有誤,請(qǐng)重新輸入。")
 ...

 1.4.3 客戶(hù)端登錄成功后,服務(wù)端會(huì)等待接收客戶(hù)端發(fā)來(lái)的命令,命令的解析,執(zhí)行由dataAnalysis.py模塊執(zhí)行,核心代碼如下:

class DataAnalysis(FileOperation):
 """
 數(shù)據(jù)分析處理類(lèi),主要負(fù)責(zé)解析client發(fā)送過(guò)來(lái)的指令。
 """
 def syntax_analysis(self,recv_data, socket_obj, commom):
 """
 負(fù)責(zé)解析客戶(hù)端傳來(lái)的數(shù)據(jù)。
 :param recv_data:接收到的客戶(hù)端用戶(hù)數(shù)據(jù)
 :param socket_obj:socket對(duì)象
 :param commom:數(shù)據(jù)對(duì)象
 :return:
 """
 clientData = recv_data.split(" ")
 if hasattr(self,clientData[0]): # 判斷對(duì)象方法是否存在
 get_fun = getattr(self,clientData[0])#獲取對(duì)象方法
 get_fun(clientData,socket_obj,commom) # 運(yùn)行對(duì)象方法
 else:
 pass
 ...

執(zhí)行客戶(hù)端命令后,繼續(xù)等待接收客戶(hù)端發(fā)來(lái)的命令,如此循環(huán)...。

2、客戶(hù)端

2.1 目錄結(jié)構(gòu)如下:

python如何實(shí)現(xiàn)簡(jiǎn)單的FTP程序

2.2 目錄簡(jiǎn)介:

client:程序主目錄。

bin:程序入口,程序啟動(dòng)文件main.py用于建立socket連接,然后調(diào)用FTPclient.py模塊下的run_ftp_client方法運(yùn)行程序。

app:程序主邏輯,目錄下有四個(gè)模塊如下:

          FTPclient.py:FTP客戶(hù)端,根據(jù)用戶(hù)選項(xiàng),執(zhí)行用戶(hù)指令。

          login.py:認(rèn)證注冊(cè)模塊,用于處理用戶(hù)注冊(cè),登錄認(rèn)證。

          dataAnalysis.py:命令解析模塊,解析用戶(hù)輸入的命令,發(fā)給服務(wù)端獲取結(jié)果。

          FileOpertion.py:負(fù)責(zé)文件讀,寫(xiě)。

lib:存放公共數(shù)據(jù),有兩個(gè)文件:

       commom.py:主要存放的是公共變量。

       help.txt:存放的是幫助文檔,當(dāng)用戶(hù)執(zhí)行help命令時(shí)會(huì)調(diào)用該文件。

2.3 模塊中類(lèi)的繼承關(guān)系

python如何實(shí)現(xiàn)簡(jiǎn)單的FTP程序

2.4 執(zhí)行流程

2.4.1 程序入口main.py,啟動(dòng)后會(huì)與FTP服務(wù)端建立連接,與服務(wù)端連接成功后會(huì)調(diào)用FTPclient.py模塊下的run_ftp_client方法,執(zhí)行用戶(hù)功能。核心代碼如下:

socket_obj = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
socket_obj.connect(("192.168.10.10",9000))

client_obj = Client()
client_obj.run_ftp_client(socket_obj) # 接收用戶(hù)輸入的選項(xiàng),執(zhí)行對(duì)應(yīng)的功能

2.4.2 FTPclient.py模塊下的run_ftp_client方法會(huì)打印菜單,并等待用戶(hù)輸入選項(xiàng),執(zhí)行相應(yīng)功能,核心代碼如下:

class Client(Login,DataAnalysis):
 def run_ftp_client(self,socket_obj):
 """
 運(yùn)行用戶(hù)輸入的選項(xiàng):1、是登陸 2、是注冊(cè)賬號(hào)
 :return:
 """
 while True:
 self.login_menu() # 打印系統(tǒng)菜單
 choice_id = self.get_user_choice() # 獲取用戶(hù)輸入的選項(xiàng)
 if choice_id:
 if self.run_user_choice(choice_id,socket_obj):
  break
 else:
 print("您輸入的有誤")
 def get_user_choice(self):
 """
 獲取用戶(hù)輸入的選項(xiàng)
 :return:
 """
 choice_id = input("請(qǐng)輸入選項(xiàng):")
 if choice_id.isdigit() and 4 > int(choice_id) > 0 or choice_id.upper() == "Q":
 return choice_id
 return False
 def run_user_choice(self,choice_id,socket_obj):
 if choice_id == "1": # 登陸系統(tǒng)
 socket_obj.send(choice_id.encode("utf-8")) # 發(fā)通知告知服務(wù)器準(zhǔn)備登陸
 if self.run_login(socket_obj) == True: # 執(zhí)行登陸
 return True
 elif choice_id == "2": # 注冊(cè)用戶(hù)
 socket_obj.send(choice_id.encode("utf-8")) # 請(qǐng)求服務(wù)器,注冊(cè)用戶(hù)
 self.register_user(socket_obj) # 執(zhí)行注冊(cè)
 elif choice_id.upper() == "Q": # 退出程序
 socket_obj.send(choice_id.encode("utf-8")) # 通知服務(wù)器,準(zhǔn)備退出程序
 socket_obj.close()
 print("程序正常退出")
 return True
 def run_login(self,socket_obj,):
 """
 運(yùn)行登陸認(rèn)證模塊,如果登陸成功執(zhí)行程序主邏輯,否則重新登陸。
 :param socket_obj:
 :return:
 """
 if self.login_authention(socket_obj):
 while True:
 send_data = input(">>>").strip(" ") # 獲取發(fā)送數(shù)據(jù)(用戶(hù)執(zhí)行的命令)
 if send_data.upper() == "Q": # 正常退出程序
  socket_obj.send(send_data.encode("utf-8")) # 通知服務(wù)區(qū)斷開(kāi)連接
  socket_obj.close()
  print("程序正常退出")
  return True
 if self.syntax_analysis(send_data, socket_obj): # 解析用戶(hù)數(shù)據(jù)并處理數(shù)據(jù)
  print("異常退出")
  return True
 return False
 def login_menu(self):
 print("-"*41)
 print(" 歡迎登陸迷你FTPv1.0")
 print("-"*41)
 print("1、登陸系統(tǒng)")
 print("2、用戶(hù)注冊(cè)")
 print("Q、退出程序")

2.4.3 login.py模塊主要用于處理注冊(cè)和登錄的功能,核心代碼如下:

class Login(Commom):
 def login_authention(self,socket_obj):
 """
 登陸認(rèn)證
 :param socket_obj:socket 對(duì)象
 :return:
 """
 user_pwd = self.get_user_pwd() # 獲取用戶(hù)名密碼
 self.send_data(socket_obj,user_pwd) # 將用戶(hù)名和密碼發(fā)給服務(wù)器
 recv_status = socket_obj.recv(2).decode("utf-8") # 等待接收狀態(tài)碼
 print(self.status_info[recv_status]) # 打印狀態(tài)碼對(duì)應(yīng)的結(jié)果
 if self.status_info[recv_status] == '登錄成功':
 return True
 return False
 ...
 def register_user(self,socket_obj):
 """
 等待服務(wù)端反饋是否允許注冊(cè)用戶(hù)。
 :param socket_obj:
 :return:
 """
 print("請(qǐng)等待服務(wù)端回應(yīng).....")
 recv_status = socket_obj.recv(1).decode("utf-8")
 if recv_status == "1": # 服務(wù)端同意申請(qǐng)賬號(hào)
 user_pwd = self.get_regist_user_pwd() # 獲取注冊(cè)用戶(hù)名和密碼
 if user_pwd:
 self.send_data(socket_obj,user_pwd)
 result = socket_obj.recv(2).decode("utf-8")
 print(self.status_info[result])
 else:
 print("用戶(hù)名密碼有誤")
 else: # 客戶(hù)端拒絕申請(qǐng)賬號(hào)的請(qǐng)求
 print("服務(wù)端拒絕了您申請(qǐng)賬號(hào)的請(qǐng)求,請(qǐng)與管理員取得聯(lián)系。")
 return False
 ...

2.4.4 用戶(hù)登錄成功后,會(huì)等待接收用戶(hù)輸入命令,由dataAnalysis.py模塊負(fù)責(zé)解析用戶(hù)輸入的命令,并將命令發(fā)給FTP服務(wù)器,然后接收服務(wù)器的反饋。核心代碼如下:

class DataAnalysis(FileOperation):
 def syntax_analysis(self,cmd,socket_obj):
 """
 解析用戶(hù)輸入的命令。
 :param cmd:用戶(hù)執(zhí)行的命令,如:put 上傳的文件
 :param socket_obj:socket對(duì)象發(fā)送和接收數(shù)據(jù)
 :return:
 """
 cmd_split = cmd.split(" ") # 將字符串命令分割成列表,用于驗(yàn)證命令是否存在
 if hasattr(self,cmd_split[0]):
 run_fun = getattr(self,cmd_split[0])
 run_fun(cmd_split,socket_obj)
 else:
 print("無(wú)效的命令")
 ...

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“python如何實(shí)現(xiàn)簡(jiǎn)單的FTP程序”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI