epoll
1. 在內核創建eventpoll結構體,返回句柄epfd(唯一標識)
? ? ? ? eventpoll包含存放被監聽的fd的紅黑樹,和存放已就緒的fd的鏈表
2. 將要監聽的fd加入到epoll紅黑樹中,并設置callback回調函數
? ? ? ? callback觸發時,就將紅黑樹的fd加入到就緒鏈表中
3. 檢查就緒鏈表是否為空,如果沒有就緒的fd,則sleep等待就緒元素進入
4. 如果不為空,返回就緒fd的數量,將內核空間就緒隊列的元素拷貝到用戶空間的events中
- select fd數量有限
- poll雖然無限,但用鏈表存儲,監聽fd過多性能不好
- epoll使用紅黑樹,遍歷效率高
LevelTriggered
- fd有數據可讀,會重復通知多次,直至數據被讀完
- epoll_wait隊列中就緒的fd復制給用戶空間后不會被立刻刪除,如果數據沒有被讀完會被重新添加回隊列
EdgeTriggered
- 當有數據可讀時只會通知一次
- epoll_wait隊列中就緒的fd復制給用戶空間后直接移除
工作流程
單線程網絡模型流程:
1. serversocket fd注冊到epoll實例,然后給他綁定一個處理器(tcpAccepthandler)
2. 在等待就緒之前調用beforesleep,然后進去等待就緒
就緒分為兩種情況:
- serverSocket有可讀事件(客戶端連接上serverSocket),然后調用serversocket的處理器,將客戶端socket fd 注冊到epoll上
- 客戶端socket可讀,調用readQueryFromClient處理器,讀取請求數據并且寫出響應
? ? ? ? a.?readQueryFromClient處理器邏輯
????????b. 給每一個客戶端封裝一個client結構體,里面有queryBuf,將讀取的數據寫入queryBuf,然后將其數據轉換為Redis命令(封裝到argv數組)
????????c. 命令用Dict封裝,根據命令名找到對應的command,執行command得到響應結果,然后把結果寫出返回給client
????????d. client存儲著buf數組和reply鏈表接受相應結果,buf數組不夠就放到reply鏈表上
????????e. 然后將客戶端添加到server.clients_pending_write隊列,等待被寫出
全局圖