epoll知识点总结
发布网友
发布时间:2022-10-18 01:17
我来回答
共1个回答
热心网友
时间:2023-11-05 13:11
epoll是linux IO多路复用的管理机制,现在是linux平台高性能网络io必要的组件。
理解内核epoll的运行原理,需要从四方面来理解:
1.epoll的数据结构。2.epoll的线程安全。
3.epoll的内核回调。4.epoll的LT与ET。
主要两个结构体 eventpoll 与 epitem。
eventpoll是每一个epoll所对应的,epitem是每一个IO所对应的事件。
数据结构图下图所示
list用来存储准备就绪的IO,内核IO准备就绪的时候,会执行epoll_event_callback的回调函数,将epitem添加到list中;当epoll_wait激活重新运行的时候,将list的epitem逐一copy到events参数中。
rbtree用来存储所有的io数据,方便快速通过io_fd查找;epoll_ctl执行EPOLL_CTL_ADD操作时,将epitem添加到rbtree中;epoll_ctl执行EPOLL_CTL_DEL操作时,将epitem从retree中删除。
以下几个包括list操作,rbtree操作,epoll_wait的等待需要加锁。
list使用最小粒度的spinlock锁,避免多核竞争。
rbtree的添加使用互斥锁,
epoll_wait采用pthread_cond_wait;
1.tcp三次握手,对端反馈ack,socket进入rcvd状态,需要将监听的socket的event置为EPOLLIN,此时标识可以进入到accept读取socket数据。
2.established状态时,收到数据,将socket的event置为EPOLLIN状态。
3.established状态时 收到fin,socket进入close_Wait,需要将socket的event设置为EPOLLIN,读取断开信息
4 . 检测到socket的send状态,cwnd >0可以发送的数据,需要将socket置为EPOLLOUT。
LT(水平触发):socket接收缓冲区不为空 有数据可读,读事件一直触发;socket发送缓冲区不满,可以继续写入数据,写事件一直触发。
ET(边缘触发):socket接收缓冲区变化时触发读事件,空的接收缓冲区刚接收到数据时触发读事件;socket发送缓冲区状态发生变化时触发写事件,即满的缓冲区刚空出空间时触发读事件。
LT的处理过程:
accept一个连接,添加到epoll中监听EPOLLIN事件。
当EPOLLIN事件到达时,read fd中的数据并处理,
当需要写出数据时,把数据write到fd中;如果数据较大,无法一次性写出,那么在epoll中监听EPOLLOUT事件。
当EPOLLOUT事件到达时,继续把数据write到fd中 ;如果数据写出完毕,那么在epoll中关闭EPOLLOUT事件。
ET的处理过程:
accept一个连接,添加到epoll中监听EPOLLIN|EPOLLOUT事件
当EPOLLIN事件到达时,read fd中数据并处理,read需要一直读,直到返回EAGAIN为止
当需要写出数据时,把数据write到fd中,直到数据全部写完或者write返回EAGAIN
当EPOLLOUT事件到达时,继续把数据write到fd中,直到数据全部写完,或者write返回EAGAIN
accept要考虑两个问题:
阻塞模式accept存在的问题:TCP连接被客户端夭折,即服务器调用accept之前,客户端主动发送RST终止连接,导致刚刚建立的连接从就绪队列中移出,如果套接口被设置成阻塞模式,服务器就一直阻塞到accept调用上,直到其他某个客户建立一个新的连接为止。在此期间,服务器 单纯阻塞在accept调用上,就绪队列上其他描述符都得不到处理。解决办法是把监听的套接口设置成非阻塞的,客户端在在服务器端调用accept之前中止某个连接时,accept调用可以立即返回-1。
ET模式accept存在的问题:
多个连接同时到达,,服务器TCP就行连接瞬间积累多个就绪连接,由于是边缘触发模式,epoll只会通知一次,accept只处理一个连接,导致TCP就绪队列中剩下的连接都得不到处理,解决办法是,while循环 中a*et调用,处理完accept就绪队列中所有连接后再退出循环。如何知道是否处理完所有连接,accept返回-1并且error设置为errno设置为EAGAIN便是所有连接都处理完。
LT 只要event为EPOLLIN时就能不断调用回调函数
ET 如果从EPOLLOUT变化为EPOLLIN时候,就会触发。