用户态的epoll实现思路?
特点:epoll和fd都是用户态的,需要自行创建、映射
一、epoll的数据结构应该是怎样的?
1.事件总积、就绪队列适合什么数据结构?
事件总集:数量不确定、需频繁的查找(效率不能低)
哈希:查找性能高于红黑树,但是内存是指数增长的,内存分配不够精准
哈希适用于:大数量、业务简单的场景
b树:查找性能不及红黑树,内存分配时成块的,不够灵活
跳表:逻辑比较复杂
红黑树:查找效率不低、内存线性增长、允许不连续的内存---(最优选)
就绪队列:双向链表
注:用户态epoll的用到2种结构体、2种数据结构,但2种数据结构的节点是共用的。
即红黑树的节点,既是黑红树本身的节点,也是就绪队列的节点;及时节点从就绪队列移除,该节点仍存在于红黑树中
二、用户态的epoll_create、epoll_ctl、epoll_wait接口是如何实现的?
1.epoll_create:创建一个事件总集的结构体,分配一个epfd(用户态的),形成映射
2.epoll_ctl:通过fd(用户态的)找到事件总集
if_add:find节点--若存在,返回节点--若不存在,分配一个节点,插入
if_delete :find节点--若存在,删除节点
if_modify:find节点,修改节点
3.epoll_wait:
第四个参数timeout
timeout<0,阻塞
timeout=0,立即返回
timeout>0,等待
一方面,设置定时器,超时就返回;
另一方面,条件等待cond_wait,
那么唤醒的时机:就绪队列每加入一个节点,就唤醒一次
三、协议栈如何与epoll协同工作?
涉及收发包中的flags和状态机
epoll3个接口与应用层交互,1个接口与协议栈交互--回调函数callbabk
那么回调函数的调用时机:
1.三次握手完成时,收到ack并且状态为syn_recvd,需callback让监听socket的event设置EPOLLIN
2.estabilshed状态,收到syn+push(有数据过来),把clientfd的event设为EPOLLIN
3.estabilshed状态,收到fin,socket进入close_wait,需要设置socket的event为EPOLLIN,读取断开信息
4.syn_send状态,对端cwnd>0,可发送数据,讲socket的event设为EPOLLOUT
四、事件什么时候从整集移至就绪队列?
调用callback的时候