IO多路转接:多路复用
IO事件控制对大量描述符进行是否具备IO条件的事件(可读/可写/异常)进行监控
作用:处理描述符的高并发事件
多路转接模型:
就绪:
读事件就绪:缓冲区有数据可读取
写事件就绪:缓冲区有空闲空间/
select:内核中通过遍历描述符集合中的描述符,判断是否相应时间就绪;若描述
符就绪了,则从集合中剔除那些没有就绪的描述符;用户通过这个集合知
道哪些描述符就绪,直接针对就绪操作
int select(int nfds,fd_set* readfds,fd_set* writefds,
fd_set* exceptfds,struct timeeval* timeout);
//nfds: maxfd+1 最大的文件描述符+1
//readfds: 可读事件集合
//writefds: 可写事件集合
//exceptfds:异常事件集合
//timeout:设置select超时等待时间
select优缺点:
优点:
(1)select遵循POSIX标准,可以跨平台,移植性好
(2)select的超时等待时间控制可以更加精细到微秒
缺点:
(1)select能够监控的描述符有上限限制,取决于_FD_SETSIZE=1024;
(2)select监控描述符原理是在内核中进行轮询遍历,性能随着描述符增多而下降
(3)select监控会修改描述符集合中的内容,因此监控时每次都要重新添加描述符
(4)select无法告诉用户哪些描述符准备就绪,需要我们用循环进行遍历
poll:
int poll(struct pollfd* fds,nfds_t nfds,int timeout);
优点:
(1)poll使用事件结构数组对描述关心的事件进行监控,简化了多个集合的监控
(2)poll没有监控的描述符上限
缺点:
(1)poll在内核中也使用轮询遍历的方式判断描述符是否就绪,性能就会随着描述符增多而下降
(2)poll也无法告诉用户哪些描述符准备就绪,需要我们用循环进行遍历判断
(3)poll也需要每次都将事件结构拷贝到内核中进行监控
epoll:
实现原理:对内核中添加的事件描述符进行监控,并且为这个描述符的事件设置事件回调函数;若
描述符就绪,则回调函数将这个事件结构放置到eventpoll结构体中的双向链表中
epoll是一个异步阻塞操作,描述符的事件监控由操作系统完成;但是epoll并不会立即返
回,而是隔一会看一下内核中的双向链表是否为空
int epoll_create(int size) //在内核中创建eventpoll结构体(保存用户关心的事件信息)
//size 能够添加的事件最大节点数量,在linux2.6.8之后被忽略,但是需要siz>0
int epoll_ctl(int epfd,int op,int fd,struct epoll_event* event);
//epfd: 创建epoll返回的epoll的句柄
//op : 对epoll要做的操作
EPOLL_CTL_ADD 向epoll结构中添加事件
EPOLL_CTL_EDL 从epoll结构中移除事件
EPOLL_CTL_MOD 修改epoll结构中事件
//fd:所监控的描述符
//event:对这个描述符要进行监控的事件 events:EPOLLIN EPOLLOUT EPOLLET EPOLLLT
//返回值: 0 失败:-1
int epoll_wait(int epfd,struct event* events,int maxevents,int timeout);
//epfd: epoll操作句柄
//events:事件结构数组
epoll每次添加的事件都会保存在内核eventpoll结构体的红黑树中;当用户调用epoll_wait开始监控,
epoll在内核中会为每一个事件都添加一个回调函数(epoll采用事件回调机制来获取描述符就绪状态);
当描述符事件就绪时,将事件地址向内核中eventpoll双向链表中添加一份(这些过程都是操作系统完成);
epoll每隔一段时间判断一下双向链表是否为空
1.为每个事件描述符的就绪定义一个信号事件(通知描述符对应事件的就绪);
2.为这个事件定义一个回调函数(将就绪的描述符对应事件信息拷贝到双向链表中)
epoll_wait发起调用之后,并不会立即返回(阻塞),而是循环判断内核中eventpoll中的双向链表是否为
空;并且以此判断,是否有描述符就绪;若有描述符就绪(双向链表不为空);再调用返回之前将就绪事件
拷贝到用户给的events结构体数组中;并且返回就绪描述符个数
3.用户操作
epoll返回所有就绪事件节点
用户通过遍历结构体数组获取到这些节点,直接对节点中保存的描述符进行操作
epoll事件触发方式:
可读事件触发
水平触发:这是epoll的默认触发方式,只要缓冲区数据大小低于低水位标记就会触发事件
边缘触发:只有新数据到来的时候才触发事件,因此要求用户最好将缓冲区的数据全部读取
但是循环读取所有数据,会造成recv阻塞;为了避免程序流程卡死
可写事件触发
水平触发:只要缓冲区空闲空间大小大于低水位标记就会触发事件
边缘触发:缓冲区空闲空间大小只有在没有空闲空间变为空闲空间的时候就触发一次
epoll优缺点:
优点:
1.监控描述符无上限
2.事件只需要向内核拷贝一次,不需要重复拷贝
3.在内核进行事件监控基于异步阻塞操作,内核以事件回调的方式进行监控;将就绪节点自动添加到双向链表
性能就不会随着描述符增多而下降
4.epoll直接返回就绪的事件节点,可以告诉用户哪些描述符就绪;用户直接对事件描述符进行操作;不需要遍历
缺点:不具备跨平台特性
IO多路转接模型的适用场景:
适用于大量描述符需要监控,但是同一时间只有少量描述符活跃的场景