1. 程式人生 > 實用技巧 >多程序併發模型--TFTP檔案伺服器

多程序併發模型--TFTP檔案伺服器

1、專案功能

  【客戶端】

    客戶端有簡單的頁面命令提示 ,功能包含

      【1】檢視伺服器檔案庫中的檔案列表(普通檔案)

      【2】可以下載其中的某個檔案到本地

      【3】可以上傳客戶端檔案到伺服器檔案庫

  【服務端】

    伺服器需求

      【1】允許多個客戶端同時操作

      【2】每個客戶端可能回連續傳送命令

2、技術分析

  【1】tcp套接字更適合檔案傳輸

  【2】併發方案 ---> fork 多程序併發

  【3】對檔案的讀寫操作

  【4】獲取檔案列表 ----> os.listdir()

  【5】粘包的處理

3、整體結構設計

  【1】伺服器功能封裝在類中(上傳,下載,檢視列表)

  【2】建立套接字,流程函式呼叫 main()

  【3】① 客戶端負責發起請求,接受回覆,展示

     ②服務端負責接受請求,邏輯處理

4、程式設計實現

  【1】搭建整體結構,建立網路連線

  【2】建立多程序和類的結構

  【3】每個功能模組的實現

【TFTP-server.py】
from
socket import * import os import signal import sys import time #檔案庫 FILE_PATH = "/home/tarena/" #實現功能模組
class TftpServer(object): def __init__(self,connfd): self.connfd = connfd def do_list(self): #獲取列表 file_list = os.listdir(FILE_PATH) if not file_list: self.connfd.send("檔案庫為空".encode()) return else: self.connfd.send(b
'OK') time.sleep(0.1) files = "" for file in file_list: if os.path.isfile(FILE_PATH+file) and \ file[0] != '.': files = files + file + '#' self.connfd.send(files.encode()) def do_get(self,filename): try: fd = open(FILE_PATH + filename,'rb') except: self.connfd.send("檔案不存在".encode()) return self.connfd.send(b'OK') time.sleep(0.1) #傳送檔案 try: while True: data = fd.read(1024) if not data: break self.connfd.send(data) except Exception as e: print(e) time.sleep(0.1) self.connfd.send(b'##') #表示檔案傳送完成 print("檔案傳送完畢") def do_put(self,filename): try: fd = open(FILE_PATH+filename,'wb') except: self.connfd.send("無法上傳".encode()) return self.connfd.send(b'OK') while True: data = self.connfd.recv(1024) if data == b'##': break fd.write(data) fd.close() print("檔案上傳完畢") #流程控制,建立套接字,建立併發,方法呼叫 def main(): HOST = '0.0.0.0' PORT = 8888 ADDR = (HOST,PORT) sockfd = socket() sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) sockfd.bind(ADDR) sockfd.listen(5) signal.signal(signal.SIGCHLD,signal.SIG_IGN) while True: try: connfd,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() tftp = TftpServer(connfd) # __init__傳參 while True: data = connfd.recv(1024).decode() if (not data) or data[0] == 'Q': print("客戶端退出") sys.exit(0) elif data[0] == "L": tftp.do_list() elif data[0] == 'G': filename = data.split(' ')[-1] tftp.do_get(filename) elif data[0] == 'P': filename = data.split(' ')[-1] tftp.do_put(filename) else: print("客戶端傳送錯誤指令") else: connfd.close() continue if __name__ == "__main__": main()

【TFTP-client.py】
from
socket import * import sys import time #實現各種功能請求 class TftpClient(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("檔案展示完畢") 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_put(self,filename): try: fd = open(filename,'rb') except: print("上傳檔案不存在") return self.sockfd.send(("P "+filename).encode()) data = self.sockfd.recv(1024).decode() if data == 'OK': while True: data = fd.read(1024) if not data: break self.sockfd.send(data) fd.close() time.sleep(0.1) self.sockfd.send(b'##') 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() sockfd.connect(ADDR) tftp = TftpClient(sockfd) #__init__是否需要傳參 while True: print("") print("==========命令選項===========") print("********** list *********") print("********** get file ******") print("********** put file ******") print("********** quit *********") print("=============================") cmd = input("輸入命令>>") if cmd.strip() == "list": tftp.do_list() elif cmd[:3] == "get": filename = cmd.split(' ')[-1] tftp.do_get(filename) elif cmd[:3] == "put": filename = cmd.split(' ')[-1] tftp.do_put(filename) elif cmd.strip() == "quit": sockfd.send(b'Q') sockfd.close() sys.exit("歡迎使用") else: print("請輸入正確命令!") if __name__ == "__main__": main()