1. 程式人生 > >yizhiyanstart的專欄

yizhiyanstart的專欄

LT(level triggered)是預設的工作方式,並且同時支援block和no-block socket.在這種做法中,核心告訴你一個檔案描述符是否就緒了,然後你可以對這個就緒的fd進行IO操作。如果你不作任何操作,核心還是會繼續通知你的,所以,這種模式程式設計出錯誤可能性要小一點。傳統的select/poll都是這種模型的代表.
ET (edge-triggered)是高速工作方式,只支援no-block socket。在這種模式下,當描述符從未就緒變為就緒時,核心通過epoll告訴你。然後它會假設你知道檔案描述符已經就緒,並且不會再為那個檔案描述符傳送更多的就緒通知,直到你做了某些操作導致那個檔案描述符不再為就緒狀態了(比如,你在傳送,接收或者接收請求,或者傳送接收的資料少於一定量時導致了一個EWOULDBLOCK 錯誤)。但是請注意,如果一直不對這個fd作IO操作(從而導致它再次變成未就緒),核心不會發送更多的通知(only once),不過在TCP協議中,ET模式的加速效用仍需要更多的benchmark確認。

epoll的介面非常簡單,一共就三個函式:

1. int epoll_create(int size);

建立一個epoll的控制代碼,size用來告訴核心這個監聽的數目一共有多大。這個引數不同於select()中的第一個引數,給出最大監聽的fd+1的值。需要注意的是,當建立好epoll控制代碼後,它就是會佔用一個fd值,在linux下如果檢視/proc/程序id/fd/,是能夠看到這個fd的,所以在使用完epoll後,必須呼叫close()關閉,否則可能導致fd被耗盡。

2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

epoll的事件註冊函式,它不同與select()是在監聽事件時告訴核心要監聽什麼型別的事件,而是在這裡先註冊要監聽的事件型別。

第一個引數是epoll_create()的返回值,

第二個引數表示動作,用三個巨集來表示:

EPOLL_CTL_ADD:註冊新的fdepfd中;

EPOLL_CTL_MOD:修改已經註冊的fd的監聽事件;

EPOLL_CTL_DEL:從epfd中刪除一個fd

第三個引數是需要監聽的fd

第四個引數是告訴核心需要監聽什麼事,struct epoll_event結構如下:

struct epoll_event {

  __uint32_t events;  /* Epoll events */

  epoll_data_t data;  /* User data variable */

};

events可以是以下幾個巨集的集合:

EPOLLIN :     表示對應的檔案描述符可以讀(包括對端SOCKET正常關閉);

EPOLLOUT:    表示對應的檔案描述符可以寫;

EPOLLPRI:      表示對應的檔案描述符有緊急的資料可讀(這裡應該表示有帶外資料到來);

EPOLLERR:     表示對應的檔案描述符發生錯誤;

EPOLLHUP:     表示對應的檔案描述符被結束通話;

EPOLLET:      將EPOLL設為邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來說的。

EPOLLONESHOT: 只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL佇列裡

3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

等待事件的產生,類似於select()呼叫。引數events用來從核心得到事件的集合,maxevents告之核心這個events有多大,這個maxevents的值不能大於建立epoll_create()時的size,引數timeout是超時時間(毫秒,0會立即返回,-1將不確定,也有說法說是永久阻塞)。該函式返回需要處理的事件數目,如返回0表示已超時。