python網路程式設計中非阻塞模式下的多客戶端請求處理
阿新 • • 發佈:2018-12-15
在預設認的情況下,TCP套節字處於阻塞模式中。換句話說,如果沒有完成操作,就不把控制權交給程式。例如呼叫connect( )API之後,連線操作會阻止程式繼續往下執行,直到連線成功為止。很多情況下,你並不想讓程式等待伺服器響應或者有異常終止操作。這裡舉個例子,如果編寫一個網頁瀏覽器客戶端連線伺服器,你應該考慮提供取消操作,以便在操作中取消連線。這時就要把套節字設定成非阻塞模式。
在python中,套節字可以被設定為阻塞模式或者非阻塞模式。在非阻塞模式下,呼叫API 後,例如send() 或recv()方法,如果遇到問題就會丟擲異常。在阻塞模式下,遇到錯誤並不會阻止操作。我們接下來建立TCP套節字,分別在阻塞模式和非阻塞模式中執行操作實驗。
為了能在阻塞模式中處理套節字,首先要建立一個套節字物件。然後呼叫setblocking(True)把套節字設為阻塞模式,或者呼叫setblocking(False)把套節字設為非阻塞模式。最後把套節字繫結到指定的埠上,監聽進入連線。
import socket import time def main(): """阻塞式接受多個客戶端請求""" # 1 建立套接字 web_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2 繫結ip和埠 埠服用 web_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) web_server.bind(("", 8080)) # 3 監聽 web_server.listen(128) # 4 服務端改成非阻塞模式 web_server.setblocking(False) # 建立當前客戶端列表 client_list = [] # 4 重複接受客戶端請求 while True: # 4 接受客戶端請求 time.sleep(1) # try exception 用來處理非阻塞時的報錯 try: # 接受客戶端 client, addr = web_server.accept() # 沒有客戶端請求連結 except Exception as ex: # print(ex) # print("沒有客戶端連結") pass # 有客戶端連結 else: print("有客戶端連結") client.setblocking(False) # 客戶端改成非阻塞模式 # 新增到客戶端列表 client_list.append(client) # 處理客戶端請求 # 遍歷客戶端列表 for client in client_list[:]: # 處理非阻塞模式下客戶端未傳送請求時的報錯 try: # 接受客戶端資料 recv_data = client.recv(8 * 1024).decode("utf-8") except Exception as e: # 客戶端未傳送請求 pass else: # 客戶端傳送請求 if recv_data: # 接受到請求資料 print(addr,"客戶端的資料", recv_data) else: # 客戶端關閉連結 print(addr, "客戶端斷開連結") # 關閉客戶端 client.close() # 從客戶端列表中刪除已關閉的客戶端 client_list.remove(client) break # 6 關閉套接字 web_server.close() if __name__ == '__main__': main() ```
執行結果
有客戶端連結 192.168.255.121
有客戶端連結 192.168.255.128
192.168.255.128 客戶端的資料 客戶2
192.168.255.121 客戶端的資料 客戶1
192.168.255.128 客戶端斷開連結
192.168.255.121 客戶端斷開連結