python實現一個簡單的ftp程式
阿新 • • 發佈:2018-11-22
客戶端可以向伺服器端下載,上傳檔案
下載檔案指令:get_filename
上傳檔案指令:put_filename
ftp工程目錄:
ftp工作原理:
put指令工作原理圖:
put指令工作原理圖:
程式碼:
客戶端:
import socket,os,json class my_ftp_client(object): def __init__(self): self.client = socket.socket() def help(self): msg = ''' get filename put filename ''' def connect(self,ip,port): # 與伺服器端建立連線,ip代表伺服器端的ip地址,port代表伺服器端的埠 self.client.connect((ip,port)) def interaction(self): # 讓使用者輸入執行,然後呼叫對應的函式來與伺服器端進行互動 while True: data = input("<<").strip() # 使用者輸入指令 if len(data)==0 : # 如果指令輸入有誤,重新輸入 continue data_one = data.split()[0] # 得到使用者輸入的操作,如果使用者如果輸入'put filename'(往伺服器端傳檔名為filename的檔案),那麼data_one就是'put' if hasattr(self,"cmd_%s"% data_one): #如果我們寫的這個類中有名為'cmd_put'的函式,就執行下面的程式碼 func = getattr(self,"cmd_%s"% data_one) # func實際上就是'cmd_put' func(data) # 呼叫類中名為'cmd_put'的函式 else : self.help() def cmd_put(self,*args): data_split = args[0].split() # 得到使用者輸入的指令 if len(data_split) > 1: # 確保指令是正確的 filename = data_split[1] # 得到檔名 if os.path.isfile(filename): # 這是個檔案 filesize = os.stat(filename).st_size msg = { #定義一個json文字,裡面儲存的是檔案的一些資訊 'action':'put', #檔案對客戶端的操作 'filename':filename,#檔名 'filesize':filesize,#檔案大小 } self.client.send(json.dump(msg).encode()) #將檔案的資訊一次性傳給伺服器端,這個地方dump是將json文字型別轉化為其他儲存格式 print('等待伺服器端返回確認指令!') server_response = self.client.recv(1024) # 接收伺服器端傳送來的確認指令 f = open(filename,'wb') for line in f: # 遍歷檔案,將檔案內容傳送給伺服器端 self.client.send(line) else : print("file end!") else : #指令是錯誤的 print("instruction error!") def cmd_get(self,*args): # 這個函式是從客戶端得到名為filename的檔案 data_split = args[0].split() # 得到使用者輸入的指令 if len(data_split) > 1: # 指令正確,執行下面的操作 file_name = data_split[1] # 得到檔名 msg = { # 定義一個json文字,裡面儲存的是檔案的一些資訊 'action': 'get', # 檔案對客戶端的操作 'filename': file_name, # 檔名 } self.client.send( json.dump(msg).encode() ) # 給伺服器端傳送這個檔案的資訊 print('等待伺服器端返回確認指令!') recevice_data = self.client.recv(1024).strip() # 接收伺服器端傳送回來的指令 data_json = json.loads(recevice_data.decode()) # 將recevice_data解析出來 One_data = data_json["instruction"] # 得到伺服器端發回來的第一個資訊 if One_data == 'Not Find': # 如果第一個資訊為'Not Find',說明伺服器端沒有名為file_name的檔案 return else : # 否則,有名為file_name的檔案 file_size = data_json["file_size"] # 得到這個檔案的大小 now_size = 0 # 當前接收到的檔案的大小 f = open(file_name,'wb') while now_size < file_size : # 開始接收檔案 data = self.client.recv(1024) f.write(data) now_size += len(data) else : print("檔案接收完畢!") ftp = my_ftp_client() ftp.connect('localhost',9999) ftp.interaction()
伺服器端:
import os,socketserver,json class MyTCPHandler(socketserver.BaseRequestHandler): def put(self,*args): data_json = args[0] # 得到json文字 filename = data_json['filename'] # 得到檔名 filesize = data_json['filesize'] # 得到檔案的大小 now_size = 0 # 這是伺服器端已經接收到的檔案的大小 if os.path.isfile(filename): # 如果伺服器端已經存在名為filename的檔案,就新建一個名為'filename.new'的檔案 f = open(filename + '.new','wb') else : # 否則,就建出名為filename的檔案 f = open(filename,'wb') self.request.send(b'200 ojbk') # 給客戶端返回伺服器端已經準備好接受檔案的資訊 while now_size < filesize: # 開始接收檔案 data = self.request.recv(1024) f.write(data) # 將接收到的檔案的內容寫入到伺服器端中的名為filename的檔案中去 now_size += len(data) # now_size加 else : print("file recv over!") # 檔案接收完畢 def get(self,*args): data_json = args[0] # 得到客戶端傳送來的資訊 file_name = data_json['filename'] # 得到客戶端想要從伺服器端獲取的檔案的檔名 if os.path.isfile(file_name): # 伺服器端有這個檔案 filesize = os.stat(file_name).st_size # 得到這個檔案的大小 msg = { #將這個檔案的資訊傳給伺服器端 "instruction": 'Find the file', # 這個資訊說明伺服器端已經找到了這個檔案了 "file_size": filesize # 返回給客戶端這個檔案的大小 } self.request.send( json.dumps(msg).encode()) f =open(file_name,'rb') # 開啟這個檔案 for line in f: # 給客戶端傳送檔案內容 self.request.send(line) else : print("檔案傳輸完畢!") else : # 伺服器端沒有這個檔案 msg = { "instruction": 'Not Find', # 這個資訊說明伺服器端沒有找到這個檔案 'file_size': 0 # 檔案大小為0 } self.request.send( json.dumps(msg).encode() ) def handle(self): while True: try: self.data = self.request.recv(1024).strip() print("{} wrote".format(self.client_address[0])) # 列印客戶端的ip地址 print("data:", self.data) data_json = json.loads(self.data.decode()) action = data_json['action'] # 得到要執行的操作 if hasattr(self,action): # 這個類中有名為action的函式 func = getattr(self,action) # func就相當於是'action' func(data_json) except ConnectionResetError as e: # 捕捉到錯誤了 print("err", e) break HOST, PORT = "localhost", 9999 server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) server.serve_forever()