Python網路程式設計--通過fork、tcp併發完成ftp檔案伺服器
阿新 • • 發佈:2018-12-15
ftp檔案伺服器
一、專案功能
1.服務端和客戶端兩部分,要求啟動一個服務端可以同時處理多個客戶端請求
2.功能:1).可以檢視服務端檔案庫中所有的普通檔案
2).從客戶端可以下載檔案庫的檔案到本地
3).可以將本地檔案上傳到服務端檔案庫
4).退出
3. 客戶端使用print在終端列印簡單的命令提示,通過命令提示發起請求
二、技術分析
1.技術分析-(fork,tcp併發)
2.每個功能要單獨封裝,整體功能寫在一個類中
3.如何搭建整體架構,完成網路通訊
三、功能分析
獲取檔案列表
客戶端: *傳送請求
*得到回覆判斷能否獲取列表
*接收檔名稱列表列印
服務端: * 接收請求
* 判斷請求型別
* 判斷能否滿足請求,回覆資訊確認
* 執行請求傳送檔案列表
-------------------------------------------------------------------------------------華麗分割線 ~_~
- 服務端程式
''' ftp 檔案伺服器 ''' from socket import * import time import os,sys import signal #檔案庫路徑 file_path = '/home/file/ftp/' HOST = '' PORT = 5000 ADDR = (HOST,PORT) #將檔案伺服器功能寫在類中 class FtpServer(object): def __init__(self,c): self.c = c def do_list(self): #獲取檔案列表 file_list = os.listdir(file_path) if not file_list: self.c.send('檔案庫為空'.encode()) return else: self.c.send(b'OK') time.sleep(0.1) files = '' for file in file_list: if file[0] != '.' and os.path.isfile(file_path+file): files = files + file + '#' self.c.sendall(files.encode()) def do_get(self,filename): try: fd = open(file_path + filename,'rb') except: self.c.send('檔案不存在'.encode()) return self.c.send(b'OK') time.sleep(0.1) #傳送檔案 while True: data = fd.read(1024) if not data: time.sleep(0.1) self.c.send(b'##') break self.c.send(data) print('檔案傳送完畢') fd.close() def do_upload(self,filename): try: fd = open(file_path+filename,'wb') except: self.c.send('檔案上傳失敗'.encode()) return self.c.send(b'OK') while True: data = self.c.recv(1024) if data == b'##': break fd.write(data) fd.close() print('%s上傳完畢'%filename) #建立套接字,接收客戶端連線,建立新的流程 def main(): sockfd = socket() sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) sockfd.bind(ADDR) sockfd.listen(5) #處理子程序退出 signal.signal(signal.SIGCHLD,signal.SIG_IGN) print('listen the port 5000...') while True: try: c,addr = sockfd.accept() except KeyboardInterrupt: sockfd.close() sys.exit('伺服器退出') except Exception as e: print('伺服器異常:',e) continue print('已連線客戶端:',addr) #建立子程序 pid = os.fork() #子程序處理具體請求 if pid == 0: sockfd.close() ftp=FtpServer(c) #判斷客戶請求 while True: data=c.recv(1024).decode() if not data: c.close() sys.exit('客戶端退出') elif data[0]=='L': ftp.do_list() elif data[0]=='G': filename=data.split(' ')[-1] ftp.do_get(filename) elif data[0]=='U': filename=data.split(' ')[-1] ftp.do_upload(filename) #父程序或者建立失敗,都繼續等待下個客戶端連線 else: c.close() continue if __name__ == '__main__': main()
- 客戶端程式
-
from socket import * from menu import show_menu import sys import time #基本檔案操作功能寫在類裡 class FtpClient(object): def __init__(self,sockfd): self.sockfd=sockfd def do_list(self): self.sockfd.send(b'L')#傳送請求 #等待回覆 data = self.sockfd.recv(1024).decode() if data == 'OK': data = self.sockfd.recv(4096).decode() files = data.split('#') for file in files: print(file) print('檔案列表展示完畢\n') else: #由伺服器傳送請求失敗原因 print(data) def do_get(self,filename): self.sockfd.send(('G '+filename).encode()) data = self.sockfd.recv(1024).decode() if data == 'OK': fd = open(filename,'wb') while True: data=self.sockfd.recv(1024) if data==b'##': break fd.write(data) fd.close() print('%s下載完畢\n'%filename) else: print(data) def do_upload(self,filename): try: fd=open(filename,'rb') except: print('檔案開啟失敗') return self.sockfd.send(('U '+filename).encode()) data=self.sockfd.recv(1024).decode() if data=='OK': while True: data=fd.read(1024) if not data: time.sleep(0.1) self.sockfd.send(b'##') break self.sockfd.send(data) fd.close() print('%s上傳完畢'%filename) else: print(data) #網路連線 def main(): if len(sys.argv) < 3: print('argv is error') return HOST = sys.argv[1] PORT = int(sys.argv[2]) ADDR = (HOST,PORT)#檔案伺服器地址/服務端地址 #建立套接字,跟服務端相同 sockfd=socket() try: sockfd.connect(ADDR) except: print('連線伺服器失敗') return ftp = FtpClient(sockfd) #功能類物件 while True: show_menu() cmd = input('請輸入命令>>:') if not cmd: break elif cmd.strip()== '1' : ftp.do_list() elif cmd.strip()[0] =='2': filename=cmd.split(' ')[-1] ftp.do_get(filename) elif cmd.strip()[0]=='3': filename=cmd.split(' ')[-1] ftp.do_upload(filename) elif cmd.strip()[0]=='4': sys.exit(0) else: print('請輸入正確命令!!!') continue # #關閉套接字 # sockfd.close() if __name__ == '__main__': main()