天天看點

I/O多路複用模型實作——epoll

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多路複用指的是這樣一個過程:

  1. 我們拿到了一堆檔案描述符(不管是網絡相關的、還是磁盤檔案相關等等,任何檔案描述符都可以)
  2. 通過調用某個函數告訴核心:“這個函數你先不要傳回,你替我監視着這些描述符,當這堆檔案描述符中有可以進行I/O讀寫操作的時候你再傳回”
  3. 當調用的這個函數傳回後我們就能知道哪些檔案描述符可以進行I/O操作了。

    也就是說通過I/O多路複用我們可以同時處理多路I/O。

epoll機制可以用來進行I/O多路複用

epoll 的核心資料結構是:1個紅黑樹和1個連結清單。還有3個核心API

I/O多路複用模型實作——epoll

熟悉一下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一樣,它也會有等待隊列。

I/O多路複用模型實作——epoll

建立epoll對象後,可以用epoll_ctl添加或删除所要監聽的socket。以添加socket為例,如下圖,如果通過epoll_ctl添加sock1、sock2和sock3的監視,核心會将eventpoll添加到這三個socket的等待隊列中

I/O多路複用模型實作——epoll

當socket收到資料後,中斷程式會操作eventpoll對象,而不是直接操作程序。

當socket收到資料後,中斷程式會給eventpoll的“就緒清單”添加socket引用。如下圖展示的是sock2和sock3收到資料後,中斷程式讓rdlist引用這兩個socket。

I/O多路複用模型實作——epoll

eventpoll對象相當于是socket和程序之間的中介,socket的資料接收并不直接影響程序,而是通過改變eventpoll的就緒清單來改變程序狀态。

當程式執行到epoll_wait時,如果rdlist已經引用了socket,那麼epoll_wait直接傳回,如果rdlist為空,阻塞程序。

假設計算機中正在運作程序A和程序B,在某時刻程序A運作到了epoll_wait語句。如下圖所示,核心會将程序A放入eventpoll的等待隊列中,阻塞程序。

I/O多路複用模型實作——epoll

當socket接收到資料,中斷程式一方面修改rdlist,另一方面喚醒eventpoll等待隊列中的程序,程序A再次進入運作狀态(如下圖)。也因為rdlist的存在,程序A可以知道哪些socket發生了變化。

I/O多路複用模型實作——epoll

繼續閱讀