1、select的些許缺點
回憶一下 select接口
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select需要我們指定文件描述符的最大值,然后取[0,nfds)這個范圍內的值查看是在集合readfds,writefds或execptfds中,也就是說這個范圍內存在一些不是我們感興趣的文件描述符,cpu做了一些無用功,poll對她進行了改進,下面就看看poll是怎么做的。
2、poll接口
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
跟select不同的是,poll不再告知內核一個范圍,而是通過struct pollfd結構體數組精確的告知內核用戶關心哪些文件描述符(流)。參數nfds指示結構體數組的大小。timeout表示程序員的忍耐度,有三種取值:
- 0,poll函數不阻塞
- 整數,阻塞timeout時間
- 負數,無限阻塞
下面來看一下struct pollfd結構體,以及其中的事件有哪些取值,及其含義
struct pollfd {
int fd; /* an open file file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
- fd屬性表示一個打開的文件描述符
- events屬性是一個輸入參數,通過bit mask的方式描述程序感興趣的事件(讀、寫)
- revents屬性是一個傳出參數,同樣式通過bit mask的方式描述發生的事件,這個屬性的值是由內核設置的。revents的值可能是events屬性的值,也可能是POLLERR,POLLHUP,POLLNVAL的一個或多個,POLLERR,POLLHUP,POLLNVAL在events屬性中是沒有意義的。
events 和 revents能夠設置的值都定義在<poll.h>頭中,有以下幾種可能
- POLLIN ,讀事件
- POLLPRI,讀事件,但表示緊急數據,例如tcp socket的帶外數據
- POLLRDNORM , 讀事件,表示有普通數據可讀
- POLLRDBAND , 讀事件,表示有優先數據可讀
- POLLOUT,寫事件
- POLLWRNORM , 寫事件,表示有普通數據可寫
- POLLWRBAND , 寫事件,表示有優先數據可寫
- POLLRDHUP (since Linux 2.6.17),Stream socket的一端關閉了連接(注意是stream socket,我們知道還有raw socket,dgram socket),或者是寫端關閉了連接,如果要使用這個事件,必須定義_GNU_SOURCE 宏。這個事件可以用來判斷鏈路是否發生異常(當然更通用的方法是使用心跳機制)。要使用這個事件,得這樣包含頭文件:
#define _GNU_SOURCE
#include <poll.h> - POLLERR,僅用於內核設置傳出參數revents,表示設備發生錯誤
- POLLHUP,僅用於內核設置傳出參數revents,表示設備被掛起,如果poll監聽的fd是socket,表示這個socket並沒有在網絡上建立連接,比如說只調用了socket()函數,但是沒有進行connect。
- POLLNVAL,僅用於內核設置傳出參數revents,表示非法請求文件描述符fd沒有打開
poll函數返回值,有三種可能
- positive number,表示struct pollfd結構體數組中有多少個非0的revents,換句話說,就是這一次調用poll發生哪些事件。
- 0,表示timeout到時,並且沒有文件描述符准備好
- -1,內部發生了錯誤,errno將會被設置
當poll返回值為-1時,表示poll出錯,errno將被設置,errno的取值有4種可能
- EFAULT ,參數struct pollfd結構體數組不在用戶地址空間,比如傳入的參數nfds比實際的數組要大。
- EINTR ,被信號中斷.
- EINVAL , nfds 超出了RLIMIT_NOFILE值.
- ENOMEM ,內核沒有足夠的內存裝載struct pollfd結構體數組
3、poll與select參數對比
使用poll()和select()不一樣,你不需要顯式地請求異常情況報告。
POLLIN | POLLPRI等價於select()的讀事件,POLLOUT |POLLWRBAND等價於select()的寫事件。POLLIN等價於POLLRDNORM |POLLRDBAND,而POLLOUT則等價於POLLWRNORM。
4、poll原理
poll的功能和select的功能一樣,只不過是參數稍微不同,poll的底層原理也和select差不多,就不多說了,I/O多路復用之select
