1. 程式人生 > >python網路程式設計中非阻塞模式下的多客戶端請求處理

python網路程式設計中非阻塞模式下的多客戶端請求處理

在預設認的情況下,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 客戶端斷開連結