一、基本知識
web
poll的機制與select相似,與select在本質上沒有多大差異,管理多個描述符也是進行輪詢,根據描述符的狀態進行處理,可是poll沒有最大文件描述符數量的限制。poll和select一樣存在一個缺點就是,包含大量文件描述符的數組被總體複製於用戶態和內核的地址空間之間,而不論這些文件描述符是否就緒,它的開銷隨着文件描述符數量的增長而線性增大。數組
二、poll函數ide
函數格式以下所示:函數
# include <poll.h>
int poll ( struct pollfd * fds, unsigned int nfds, int timeout);
pollfd結構體定義以下:spa
struct pollfd {指針
int fd; /* 文件描述符 */
short events; /* 等待的事件 */
short revents; /* 實際發生了的事件 */
} ; orm
每個pollfd結構體指定了一個被監視的文件描述符,能夠傳遞多個結構體,指示poll()監視多個文件描述符。每一個結構體的events域是監視該文件描述符的事件掩碼,由用戶來設置這個域。revents域是文件描述符的操做結果事件掩碼,內核在調用返回時設置這個域。events域中請求的任何事件均可能在revents域中返回。合法的事件以下:blog
POLLIN 有數據可讀。索引
POLLRDNORM 有普通數據可讀。進程
POLLRDBAND 有優先數據可讀。
POLLPRI 有緊迫數據可讀。
POLLOUT 寫數據不會致使阻塞。
POLLWRNORM 寫普通數據不會致使阻塞。
POLLWRBAND 寫優先數據不會致使阻塞。
POLLMSGSIGPOLL 消息可用。
此外,revents域中還可能返回下列事件:
POLLER 指定的文件描述符發生錯誤。
POLLHUP 指定的文件描述符掛起事件。
POLLNVAL 指定的文件描述符非法。
這些事件在events域中無心義,由於它們在合適的時候老是會從revents中返回。待監聽的事件由events成員指定,函數在相應的revents成員中返回該描述符的狀態(每一個文件描述符都有兩個事件,一個是傳入型的events,一個是傳出型的revents,從而避免使用傳入傳出型參數,注意與select的區別),從而告知應用程序fd上實際發生了哪些事件。events和revents均可以是多個事件的按位或。
timeout參數指定等待的毫秒數,不管I/O是否準備好,poll都會返回。timeout指定爲負數值表示無限超時,使poll()一直掛起直到一個指定事件發生;timeout爲0指示poll調用當即返回並列出準備好I/O的文件描述符,但並不等待其它的事件。這種狀況下,poll()就像它的名字那樣,一旦選舉出來,當即返回。
返回值和錯誤代碼
成功時,poll()返回結構體中revents域不爲0的文件描述符個數;若是在超時前沒有任何事件發生,poll()返回0;失敗時,poll()返回-1,並設置errno爲下列值之一:
EBADF 一個或多個結構體中指定的文件描述符無效。
EFAULTfds 指針指向的地址超出進程的地址空間。
EINTR 請求的事件以前產生一個信號,調用能夠從新發起。
EINVALnfds 參數超出PLIMIT_NOFILE值。
ENOMEM 可用內存不足,沒法完成請求。
三、經過poll向stdin輸入數據並回顯,timeout設置爲5000ms
代碼:
#include <stdio.h> #include <poll.h> int main() { struct pollfd fd_ev[1]; fd_ev[0].fd = 0; fd_ev[0].events = POLLIN; fd_ev[0].revents = 0; int done = 0; while(!done){ int timeout =5000; switch( poll(fd_ev, 1, timeout) ){ case -1: perror("poll"); break; case 0: printf("timeout...\n"); break; default: { if(fd_ev[0].revents & POLLIN){ char buf[1024]; ssize_t _s = read(fd_ev[0].fd, buf, sizeof(buf)-1); if( _s > 0 ){ buf[_s-1] = '\0'; printf("echo: %s\n", buf); } } } break; } } }
四、poll的特色
a)poll把文件描述符和事件綁定,而且事件能夠單獨指定,而且能夠是多個事件的按位或,這樣更加細化了事件的註冊,並且poll單獨採用一個元素用來保存就緒返回時的結果,這樣在下次調用poll時,就不用重置以前註冊的事件;
b)poll採用對全部註冊的文件描述符集輪詢的方式,會返回整個用戶註冊的事件集合,因此應用程序索引就緒文件的時間複雜度爲O(n)。
c)poll用nfds參數指定最多監聽多少個文件描述符和事件,這個數能達到系統容許打開的最大文件描述符數目,即65535。
d)只能工做在LT模式。
五、poll的優勢
1)poll與select不一樣,經過一個pollfd數組向內核傳遞須要關注的事件,故沒有描述符個數的限制,pollfd中的events字段和revents分別用於標示關注的事件和發生的事件,故pollfd數組只須要被初始化一次。
2)poll的實現機制與select相似,其對應內核中的sys_poll,只不過poll向內核傳遞pollfd數組,而後對pollfd中的每一個描述符進行poll,相比處理fdset來講,poll效率更高。
六、poll的缺點
1)雖然fd沒有限制,可是事實上,同事鏈接的客戶端在時刻可能只有不多的處於就緒狀態,所以隨着監視的描述符數量的增加,其效率也會線性降低。
2)每次調用poll,存在由用戶到內核的拷貝,開銷大
3)每次調用poll,都要輪詢檢測events數組中fd的revents是否是和其events相同,開銷大