標籤:
1、相關宏和函數原型
FD_ZERO(int fd, fd_set* fds) FD_SET(int fd, fd_set* fds) FD_ISSET(int fd, fd_set* fds) FD_CLR(int fd, fd_set* fds) int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
這裡,fd_set 類型可以簡單的理解為按 bit 位標記控制代碼的隊列,例如要在某 fd_set 中標記一個值為 16 的控制代碼,則該 fd_set 的第 16 個 bit 位被標記為 1。具體的置位、驗證可使用 FD_SET、FD_ISSET 等宏實現。在 select() 函數中,readfds、writefds 和 exceptfds 同時作為輸入參數和輸出參數。如果輸入的 readfds 標記了 16 號控制代碼,則 select() 將檢測 16 號控制代碼是否可讀。在 select() 返回後,可以通過檢查 readfds 有否標記 16 號控制代碼,來判斷該“可讀”事件是否發生。另外,使用者可以設定 timeout 時間。
2、伺服器操作流程
這裡需要指出的是,用戶端的一個 connect() 操作,將在伺服器端激發一個“可讀事件”,所以 select() 也能探測來自用戶端的 connect() 行為。
上述模型中,最關鍵的地方是如何動態維護 select() 的三個參數 readfds、writefds 和 exceptfds。作為輸入參數,readfds 應該標記所有的需要探測的“可讀事件”的控制代碼,其中永遠包括那個探測 connect() 的那個“母”控制代碼;同時,writefds 和 exceptfds 應該標記所有需要探測的“可寫事件”和“錯誤事件”的控制代碼 ( 使用 FD_SET() 標記 )。
作為輸出參數,readfds、writefds 和 exceptfds 中的儲存了 select() 捕捉到的所有事件的控制代碼值。程式員需要檢查的所有的標記位 ( 使用 FD_ISSET() 檢查 ),以確定到底哪些控制代碼發生了事件。
上述模型主要類比的是“一問一答”的服務流程,所以,如果 select() 發現某控制代碼捕捉到了“可讀事件”,伺服器程式應及時做 recv() 操作,並根據接收到的資料準備好待發送資料,並將對應的控制代碼值加入 writefds,準備下一次的“可寫事件”的 select() 探測。同樣,如果 select() 發現某控制代碼捕捉到“可寫事件”,則程式應及時做 send() 操作,並準備好下一次的“可讀事件”探測準備。描述的是上述模型中的一個執行循環。
redis-網路事件模型(scoket)