在I/O复用中,相比较select,poll就要聪明一些,先看一下poll原型
int poll(struct pollfd * fds, int nfds, int timeout);
- fds:传入的是数组
- nfds:数组长度
- timeout:定时时间,设为-1,永久阻塞
- 返回值>0表示就绪文件个数,为零说明无就绪,<0表示出错
从参数可以看出,poll传入的文件描述符个数并不受限制
struct pollfd
{
int fd//文件描述符
short events;//事件类型
short revents;//返回时内核填充
}
从结构变量类型可以看出,文件描述符的可取范围更大,并且可以描述的事件类型更多,而且内核需要修改的和原本的事件类型不是一个变量,所以不需要重新设置
但整体来看最终还是需要自行检测哪一个文件描述符就绪,时间复杂度为O(n)
- int listenfd = CreateSocket();//此处将创建监听套接字,地址与端口号进行绑定操作封装为该函数完成
struct pollfd fds[FDSZIE]//FDSIZE是数组大小的宏,创建一个数组来记录文件描述符以及事件类型随后进行初始化,并且将监听套接字插入,事件类型为POLLIN
这里我们只关注两种事件类型 POLLIN 读数据以及 POLLRDHUP断开 - while(1){//进入循环
int n = poll(fds, 100, -1);//调用poll,返回就绪个数
往下的处理是封装在一起的在DealReadyfds();
//所有的文件描述符进行遍历
//如果当前fds[i].fd为-1,为无效描述符,跳过 - // 3.如果是监听套接字且POLLIN事件,那么获取新连接,且插入数组
accept;
Insertfds; - // 4.若果是连接套接字分类处理: POLLRDHUP 断开 POLLIN 接收数据
if(fds[i].events & POLLRDHUP)//断开
else if(fds[i].revents & POLLIN)//收发数据
recv/send - }//循环结束