epoll IO多路複用模型實作機制
-
- I/O多路複用
- epoll
-
- epoll_create(int size)
- epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
- epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)
- epoll event
- epoll流程
I/O多路複用
I/O 多路複用的本質,是通過一種機制(系統核心緩沖I/O資料),讓單個程序可以監視多個檔案描述符,一旦某個描述符就緒(一般是讀就緒或寫就緒),能夠通知程式進行相應的讀寫操作。
所謂I/O多路複用指的是這樣一個過程:
- 我們拿到了一堆檔案描述符(不管是網絡相關的、還是磁盤檔案相關等等,任何檔案描述符都可以)
- 通過調用某個函數告訴核心:“這個函數你先不要傳回,你替我監視着這些描述符,當這堆檔案描述符中有可以進行I/O讀寫操作的時候你再傳回”
-
當調用的這個函數傳回後我們就能知道哪些檔案描述符可以進行I/O操作了。
也就是說通過I/O多路複用我們可以同時處理多路I/O。
epoll機制可以用來進行I/O多路複用
epoll 的核心資料結構是:1個紅黑樹和1個連結清單。還有3個核心API
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL3YmM3MDN5YjZykzNkJjZ4QzN4QTN1YDZzYDM4QzNhVzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
熟悉一下epoll
epoll
epoll_create(int size)
建立一個epoll的句柄,size用來告訴核心這個監聽的數目一共有多大
epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
第一個參數是epoll_create()的傳回值
第二個參數表示動作
EPOLL_CTL_ADD:注冊新的fd到epfd中
EPOLL_CTL_MOD:修改已經注冊的fd的監聽事件
EPOLL_CTL_DEL:從epfd中删除一個fd
第三個參數是需要監聽的fd
第四個參數是告訴核心需要監聽什麼事,在被監測的檔案描述符上實際發生的事件。
epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)
第1個參數 epfd是 epoll的描述符
第2個參數 events則是配置設定好的 epoll_event結構體數組,epoll将會把發生的事件複制到 events數組中
第3個參數 maxevents表示本次可以傳回的最大事件數目,通常 maxevents參數與預配置設定的events數組的大小是相等的
第4個參數 timeout表示在沒有檢測到事件發生時最多等待的時間(機關為毫秒),如果 timeout為0,則表示 epoll_wait在 rdllist連結清單中為空,立刻傳回,不會等待;timeout = -1表示調用将一直阻塞,直到有檔案描述符進入ready狀态或者捕獲到信号才傳回
epoll event
EPOLLIN:描述符處于可讀狀态
EPOLLOUT:描述符處于可寫狀态
EPOLLET:将epoll event通知模式設定成edge triggered
EPOLLONESHOT:第一次進行通知,之後不再監測
EPOLLHUP:本端描述符産生一個挂斷事件,預設監測事件
EPOLLRDHUP:對端描述符産生一個挂斷事件
EPOLLPRI:由帶外資料觸發
EPOLLERR:描述符産生錯誤時觸發,預設檢測事件
epoll流程
Epoll流程:
當某個程序調用epoll_create方法時,核心會建立一個eventpoll對象(也就是程式中epfd所代表的對象)。eventpoll對象也是檔案系統中的一員,和socket一樣,它也會有等待隊列。
建立epoll對象後,可以用epoll_ctl添加或删除所要監聽的socket。以添加socket為例,如下圖,如果通過epoll_ctl添加sock1、sock2和sock3的監視,核心會将eventpoll添加到這三個socket的等待隊列中
當socket收到資料後,中斷程式會操作eventpoll對象,而不是直接操作程序。
當socket收到資料後,中斷程式會給eventpoll的“就緒清單”添加socket引用。如下圖展示的是sock2和sock3收到資料後,中斷程式讓rdlist引用這兩個socket。
eventpoll對象相當于是socket和程序之間的中介,socket的資料接收并不直接影響程序,而是通過改變eventpoll的就緒清單來改變程序狀态。
當程式執行到epoll_wait時,如果rdlist已經引用了socket,那麼epoll_wait直接傳回,如果rdlist為空,阻塞程序。
假設計算機中正在運作程序A和程序B,在某時刻程序A運作到了epoll_wait語句。如下圖所示,核心會将程序A放入eventpoll的等待隊列中,阻塞程序。
當socket接收到資料,中斷程式一方面修改rdlist,另一方面喚醒eventpoll等待隊列中的程序,程序A再次進入運作狀态(如下圖)。也因為rdlist的存在,程序A可以知道哪些socket發生了變化。