既然已经有select实现IO多路转接了,为什么还要有poll?
之前说过select有很多的缺点:
而poll的出现解决了select的两个问题:
1、可监控的文件描述符个数有上限
2、参数即作为输入参数又做输出
poll函数的声明:
int poll(struct pollfd* fds, nfds_t nfds, int timeout)
参数解释:
1、fds:监听结构列表,包含三部分内容(文件描述符,监听的事件集合,返回的事件集合)
struct pollfd结构:
events和recvents的取值,这里仅介绍可读和可写:
数据可读:POLLIN
数据可写:POLLOUT
2、fds数组长度
3、timeout:等待时间,单位是毫秒
所以poll的使用,一般是先定义一个struct pollfd类型的数组,假设要监视0号文件描述符的读事件,就把数组的第一个元素的fd设为0,events设为POLLIN,而revents为返回,当数组的第一个元素的revents变为POLLIN,表示0号文件描述符的读事件就绪。
返回值解释:
大于0:监听的文件描述符就绪,poll返回
等于0:超时返回
小于0:出错
socket就绪条件
sochet内核中,接收缓冲区中的字节数,大于等于低水位标记SO_RECVLOWAT,此时可以无阻塞的读该文件描述符,并且返回值大于0
socket TCP通信中,对端关闭连接,此时对该socket读,则返回0
监听的socket上有新的连接请求时
socket上有未处理的错误时
socket内核中,发送缓冲区中的可用字节数(发送缓冲区的空闲位置大小),大于等于低水位标记,SO_SNDLOWAT,此时可以无阻塞的写,并且返回值大于0
socket的写操作被关闭(close或者shutdown),对于一个写操作被关闭的socket进行写操作,会触发SIGPIPE信号
socket使用非阻塞connect连接成功或失败之后
socket上有未读取的错误
socket上收到带外数据(关于带外数据,和TCP紧急模式相关,在TCP报头中有一个紧急指针的字段)
编写poll代码:
一、检测标准输入
1 #include
2 #include
3 #include
4
5 int main(){
6 // 因为只关心一个文件描述符,所以就不定义数组了,第二个参数填1就好
7 // 关心0号文件描述符(标准输入)的读事件
8 struct pollfd poll_fd;
9 poll_fd.fd = 0; // 标准输入
10 poll_fd.events = POLLIN; // 读事件
11 // poll_fd.revents为输出型,返回事件的集合
12 while(1){
13 int ret = poll(&poll_fd,1,3000); // 数组大小为1,等待时间为3000ms(3秒)
14 if(ret < 0){
15 printf("poll error\n");
16 continue;
17 }
18 if(ret == 0){
19 printf("poll timeout\n");
20 continue;
21 }
22 if(poll_fd.revents == POLLIN){// 当0的读事件就绪时
23 char buf[1024] = {0};
24 read(0,buf,sizeof(buf)-1);
25 printf("input:%s\n", buf);
26 }
27 }
28 return 0;
29 }
运行效果为超过3秒不往标准输入写数据,poll会立刻超时返回,如果想标准输入写数据,则标准输入的读会就绪,然后把数据回显.
二、模拟实现poll服务器
//初始化监控列表数组,把fd设为-1,监听和返回事件设为0
void Initpolled(struct pollfd* fd_list,int size)
{
int i = 0;
for(i = 0; i: $s\n",buf);
}
}
}
return 0;
}
客户端和select相同。
poll的优点:
不同于select使用三个位图来表示三个fdset的方式,poll使用一个pollfd的指针实现
1、pollfd结构包含了要监视的enent和发生的event,不再使用select“参数-值”传递的方式,接口使用比select更加方便
2、poll并没有最大数量限制(但是数量过大后性能也是会下降)
poll的缺点
poll中监听的文件描述符增多时:
1、和select一样,poll返回后,需要轮询pollfd来获取就绪的文件描述符
2、每次调用poll函数都需要把大量的pollfd结构从用户态拷贝到内核中
3、同时连接的大量客户端在同一时刻可能只有很少的处于就绪状态,因此随着监视的文件描述符数量的增长,其效率也会线性下降
1、poll返回后也需要轮询fd_list列表来获取就绪的文件描述符
2、需要把polled从用户态拷贝至内核态
3、虽然没有数量限制,但是数量过大,性能也会线性下降