poll基本知识
前一篇:高级IO之select(点击直达)讲解了select,下面来看一下poll.
poll的机制和select,管理多个描述符也是进行轮询,根据描述符的状态进行处理,区别是poll没有最大文件描述符数量的限制。
poll函数接口
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
参数说明:
- fds是一个poll函数监听的结构列表. 每一个元素中, 包含了三部分内容: 文件描述符, 监听的事件集合, 返回的事件集合.
- nfds表示fds数组的长度.
- timeout表示poll函数的超时时间, 单位是毫秒(ms)
pollfd结构:
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
fd是哪个文件描述符,events:用户告诉内核你要帮我关心哪个文件描述符上的什么事件,revent:内核告诉用户,文件描述符上的事件已经就绪了。
events和revents的取值:
事件 | 描述 | 是否可作为输入 | 是否可作为输出 |
---|---|---|---|
POLLIN | 数据(包括普通数据和优先数据) | 是 | 是 |
POLLRDNORM | 普通数据可读 | 是 | 是 |
POLLRDBAND | 优先数据可读(Linux不支持) | 是 | 是 |
POLLPRI | 高优先级数据可读,比如TCP外带数据 | 是 | 是 |
POLLOUT | 数据(包括普通数据和优先数据) | 是 | 是 |
POLLWRNORM | 普通数据可写 | 是 | 是 |
POLLWRBAND | 优先级带数据可写 | 是 | 是 |
POLLRDHUP | TCP连接被对方关闭,或者对方关闭了写操作 | 是 | 是 |
POLLERR | 错误 | 否 | 是 |
POLLHUP | 挂起 | 否 | 是 |
POLLNVAL | 文件描述符没有打开 | 否 | 是 |
我们常用的就是读和写事件。
返回值
- 返回值小于0, 表示出错;
- 返回值等于0, 表示poll函数等待超时;
- 返回值大于0, 表示poll由于监听的文件描述符就绪而返回
poll的优缺点
poll优点
- pollfd结构包含了要监视的event和发生的event,不再使用select“参数-值”传递的方式. 接口使用比
select更方便. - poll并没有最大数量限制 (但是数量过大后性能也是会下降).
poll缺点
poll中监听的文件描述符数目增多时
- 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符.
- 每次调用poll都需要把大量的pollfd结构从用户态拷贝到内核中.
- 同时连接的大量客户端在一时刻可能只有很少的处于就绪状态, 因此随着监视的描述符数量的增长, 其效率也会线性下降.
用poll简单监控标准输入
1 #include <poll.h>
2 #include <unistd.h>
3 #include <iostream>
4 using namespace std;
5 int main() {
6 struct pollfd poll_fd;
7 poll_fd.fd = 0;
8 poll_fd.events = POLLIN;
9
10 for (;;) {
11 int ret = poll(&poll_fd, 1, 1000);
12 if (ret < 0) {
13 cerr<<"poll"<<endl;
14 continue;
15 }
16 if (ret == 0) {
17 cout<<"poll timeout"<<endl;
18 continue;
19 }
20 if (poll_fd.revents == POLLIN