1. 程式人生 > >解讀併發伺服器之poll和epoll函式

解讀併發伺服器之poll和epoll函式

  前言

  之前已經介紹過select函式,請參考這篇部落格:https://www.cnblogs.com/liudw-0215/p/9661583.html,原理都是類似的,有時間先閱讀下那篇部落格,以便於理解這篇部落格。

  一、poll函式

  1、函式說明

  原型:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
  引數說明: 

  引數fds:

  struct pollfd {

int fd; /* 檔案描述符 */

short events; /* 監控的事件 */

short revents; /* 監控事件中滿足條件返回的事件 */

};

POLLIN 普通或帶外優先資料可讀,即POLLRDNORM | POLLRDBAND

POLLRDNORM 資料可讀

POLLRDBAND 優先順序帶資料可讀

POLLPRI 高優先順序可讀資料

POLLOUT 普通或帶外資料可寫

POLLWRNORM 資料可寫

POLLWRBAND 優先順序帶資料可寫

POLLERR 發生錯誤

POLLHUP 發生掛起

POLLNVAL 描述字不是一個開啟的檔案

nfds:監控陣列中有多少檔案描述符需要被監控

timeout:毫秒級等待

-1:阻塞等,#define INFTIM -1 Linux中沒有定義此巨集

0:立即返回,不阻塞程序

>0:等待指定毫秒數,如當前系統時間精度不夠毫秒,向上取值

  如果不再監控某個檔案描述符時,可以把pollfd中,fd設定為-1,poll不再監控此pollfd,下次返回時,把revents設定為0。

  2、程式示例

  理解select之後,再解poll就很簡單了,服務端程式碼如下:

View Code

  程式中封裝了包裹函式,有需要的請評論留言。

  二、epoll函式

  1、介紹 

  epoll是Linux下多路複用IO介面select/poll的增強版本,它能顯著提高程式在大量併發連線中只有少量活躍的情況下的系統CPU利用率,因為它會複用檔案描述符集合來傳遞結果而不用迫使開發者每次等待事件之前都必須重新準備要被偵聽的檔案描述符集合,另一點原因就是獲取事件的時候,它無須遍歷整個被偵聽的描述符集,只要遍歷那些被核心IO事件非同步喚醒而加入Ready佇列的描述符集合就行了。

  目前epell是linux大規模併發網路程式中的熱門首選模型。

  epoll除了提供select/poll那種IO事件的電平觸發(Level Triggered)外,還提供了邊沿觸發(Edge Triggered),這就使得使用者空間程式有可能快取IO狀態,減少epoll_wait/epoll_pwait的呼叫,提高應用程式效率。

  2、函式說明

  跟select和poll不一樣,epoll不是一個函式,需要三個函式一起來實現,分別為epoll_create、epoll_ctl和epoll_wait,下面分別來說明這三個函式。

  (1)epoll_create函式

  功能:建立一個epoll,引數size用來告訴核心監聽的檔案描述符的個數,跟記憶體大小有關。

  原型:int epoll_create(int size)

  又到了上圖時間了,如下圖:  PS:依舊是全部落格園最醜圖,不接受反駁。

  

  epoll_create返回的epfd,其實建立了紅黑樹,是它的根節點。

  (2)epoll_ctl函式

  功能:控制某個epoll監控的檔案描述符上的事件:註冊、修改、刪除。

  原型:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

  引數說明: 

epfd: 為epoll_creat的

op: 表示動作,用3個巨集來表示:

EPOLL_CTL_ADD (註冊新的fd到epfd),

EPOLL_CTL_MOD (修改已經註冊的fd的監聽事件),

EPOLL_CTL_DEL (從epfd刪除一個fd);

event: 告訴核心需要監聽的事件

struct epoll_event {

__uint32_t events; /* Epoll events */

epoll_data_t data; /* User data variable */

};

typedef union epoll_data {

void *ptr;

int fd;

uint32_t u32;

uint64_t u64;

} epoll_data_t;

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

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

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

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

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

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

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

  (3)epoll_wait函式

  功能:等待所監控檔案描述符上有事件的產生

  原型:int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)

  引數說明:  

events: 用來存核心得到事件的集合,

maxevents: 告之核心這個events有多大,這個maxevents的值不能大於建立epoll_create()時的size,

timeout: 是超時時間

-1: 阻塞

0: 立即返回,非阻塞

>0: 指定毫秒

返回值: 成功返回有多少檔案描述符就緒,時間到時返回0,出錯返回-1

  3、示例程式

  服務端程式如下:

View Code

  總結:需要包裹函式、客戶端等程式的,歡迎留言