1. 程式人生 > >詳解網絡編程必會的poll和epoll函數

詳解網絡編程必會的poll和epoll函數

logs 之前 eve 原理 成功 epoll 模型 orm create

  前言

  之前已經介紹過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

  

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

詳解網絡編程必會的poll和epoll函數