IO多路转接
@(Linux)
1.基本概念
适合场景
多用于有大量链接,但同一时间活跃量较小
2.select
2.1基本流程
- IO多路转接的第一种模型,服务器端能够同时监控多个客户端的套接字,当有事件发生时,进行相应的操作
- 事件发生:创建新链接,读操作,写操作,异常处理
- 文件描述符数组:用户自定义,用于存放套字
- 内核位图:三种文件描述符集合,系统等待直到有文件描述符状态改变
2.2函数原语
#include
2.3优缺点
- 优点
- 可以跨平台
- 缺点
- 描述符有上限 集合中有1024位
- 数据每次都从用户态拷贝到内核态,自定义数组->集合
- 轮询遍历数组,所以描述越多,效率越低
- 重新添加,每次有事件就绪时,监控的文件描述符状态改变,数组重新添加到集合
- 编码复杂度较高
3.poll
3.1基本流程
pollfd结构体,用于记录世界
3.2函数原语
struct pollfd {
int fd; //文件描述符
short events; //监控的集合
short revents; //返回的集合
}
int poll(struct pollfd* fds, nfds_t nfds, int timeout);
fds 可以表示结构体列表,多个结构体
3.3优缺点
- 优点
- 在资源足够下,描述符无上限
- 编码复杂度较低
- 缺点
- 态拷贝
- 轮询遍历 描述符增加性能降低
- 不可跨平台
4.epoll
4.1基本流程
建立一个文件描述符集合(监控队列),在内核态有一个就绪队列,有事件就绪时加入到就绪队列
struct epoll_event 事件结构体
fd/ptr
event_poll 红黑树–监控队列,双向链表–就绪列
事件触发回调—事件触发,回调函数知道是什么事件,红黑树搜索找到事件,插入双向链表;用户自定义数组,从链表中拷贝,操作
4.2函数原语
epoll_create
epoll_ctl(EPOLL_CTL_ADD) //添加到监控队列
epoll_wait()
int nfds epoll_wait(struct epoll_event[]) 等待监控, 就绪添加到自定义数组epoll_event
- LT模式 水平触发 :只要新事件满足就绪条件就会一直返回通知我们;一共10字节,每次接受2字节,通知5次
- ET模式 边缘触发 :只有每次新事件就绪的时候才会返回给我们通知;一共10字节,每次接受2字节,直到把缓存区数据读完,最后通知1次;若缓存区已读完,但对端的写端没有关闭,所以会一直阻塞;
- 一次将所有数据读取出来,否则不会再次提醒,直到下次新数据到了,才提醒;有可能造成recv阻塞,因此需要socket设置为非阻塞;
- 惊群效应: 多服务器,负载均衡
4.3优缺点
- 优点
- 描述符无上限
- 事件回调,不会随着描述符的增加,性能下降;
- 每个事件只需添加到内核态一次,不需要重复添加,效率高
- 编码难道较小
- 就绪事件直接交付发我们,直接遍历,不用多余的遍历;
- 缺点
- 不可跨平台