一、poll系統調用
poll 和select類似,是在指定時間內輪詢一定數量的文件描述符,以測試其中是否有就緒者。
poll的原型爲:
#include <poll.h>
int poll(struct pollfd* fds, nfds_t nfds, int timeout);
返回值:
成功時,返回pollfd結構體中域revents不爲0的文件描述描述符的個數(即數組fds中準備好讀、寫或出錯狀態的那些socket描述符的總數量);如果在超時前沒有事件發生,則返回0;
失敗,返回-1。
1),fds參數是一個pollfd結構類型的數組,它指定所有我們感興趣的文件描述符上發生的可讀、可寫和異常等事件。pollfd結構體定義爲:
struct pollfd
{
int fd; //文件描述符
short events; //註冊的事件
short revents; //實際發生的事件,由內核填充
}
fd成員指定文件描述符;
events成員告訴poll監聽fd上的哪些事件,它是一系列事件的按位或;
revents成員則由內核修改,已通知應用程序fd上實際發生了哪些事件。
poll支持監控的事件類型如下:
事件 | 描述 | 是否可作爲輸入 | 是否可作爲輸出 |
POLLIN | 數據(包括普通數據和優先數據)可讀 | 是 | 是 |
POLLRDNORM | 普通數據可讀 | 是 | 是 |
POLLRDBAND | 優先級帶數據可讀(linux不支持) | 是 | 是 |
POLLPRI | 高優先級數據可讀,比如TCP帶外數據 | 是 | 是 |
POLLOUT | 數據(包括普通數據和優先數據)可寫 | 是 | 是 |
POLLWRNORM | 普通數據可讀寫 | 是 | 是 |
POLLWRBAND | 優先級帶數據可寫 | 是 | 是 |
POLLRDHUP | TCP連接被對方關閉,或者對方關閉了寫操作。它由GNU引入 | 是 | 是 |
POLLERR | 錯誤 | 否 | 是 |
POLLHUP | 掛起。比如管道的寫端被關閉後,讀端描述符上將收到POLLHUP事件 | 否 | 是 |
POLLNVAL | 文件描述符沒有打開 | 否 | 是 |
#define POLLIN 0x0001
#define POLLPRI 0x0002
#define POLLOUT 0x0004
#define POLLERR 0x0008
#define POLLHUP 0x0010
#define POLLNVAL 0x0020
#define POLLRDNORM 0x0040
#define POLLRDBAND 0x0080
#define POLLWRNORM 0x0100
#define POLLWRBAND 0x0200
#define POLLMSG 0x0400
#define POLLREMOVE 0x1000
#define POLLRDHUP 0x2000
2),nfds參數指定被監聽事件集合fds的大小、其類型nfds_t的定義如下:
typedef unsigned long int nfds_t;
3),timeout參數指定poll的超時值,單位是毫秒。
當timeout爲-1時,poll調用將永遠阻塞i,直到某個事件發生;
當timeout爲0時,poll調用將立即返回;
當timeout大於0時,爲超時時間。
二、poll和epoll在使用上的區別
1),如何索引poll返回的就緒文件描述符
int ret = poll(fds, MAX_EVENT_NUMBER, -1);
//必須遍歷所有已註冊文件描述符並找到其中的就緒者(當然也可用ret來優化)
for(int i = 0; i < MAX_EVENT_NUMBER; ++i)
{
//判斷第i個文件描述符是否就緒
if(fds[i].revents & POLLIN)
{
int sockfd = fds[i].fd;
//處理sockfd
}
}
2), 如何索引epoll返回的就緒文件描述符
int ret = epoll_wait(epollfd, events, MAX_EVENT_NUBER, -1);
//僅遍歷就緒的ret個文件描述符
for(int i = 0; i < ret; i++)
{
int sockfd = events[i].data.fd;
//sockfd肯定就緒,直接處理
}