用户态协议栈之epoll实现

Epoll Linux IO 多路复用的管理机制。作为现在 Linux 平台高性能网络 IO 必要的组件。内
核的实现可以参照: fs/eventpoll.c .
在实现 epoll 之前,先得好好理解内核 epoll 的运行原理。内核的 epoll 可以从四方面来理解。
1. Epoll 的数据结构, rbtree <fd, event> 的存储, ready 队列存储就绪 io
2. Epoll 的线程安全, SMP 的运行,以及防止死锁。
3. Epoll 内核回调。
4. Epoll LT (水平触发)与 ET (边沿触发)
下面从这四个方面来实现 epoll

一、 Epoll 数据结构

如何更好的管理大量的fd?

所有的fd有只有两种状态,就绪状态和空闲状态

就绪状态占少量,大部分的fd都处于空闲状态

那么空闲状态的fd用什么存储?                

空闲状态的fd节点需要满足索引速度快的的条件

{        

        索引速度快:

                1.hash    查找速度快,但是不利于扩展,也就是说如果需要加入一个装有fd的节点,很麻烦

                2 红黑数(avl)  查找速度快,扩展性强

                3 b/b+树 节点比较大,不适合存索引适合磁盘索引

                4 调表 存在概率问题,并不可取

      }

综上所述:空闲状态的fd节点采用红黑树存储

就绪fd节点采用队列存储比较好?

不仅是因为就绪状态的fd的数量比较少,而且是就绪队列的fd节点不需要遍历,只需要一次取出来用即可。

链式结构:队列 和 栈

为什么不采用栈而采用队列?队列是先进先出,而栈是先进后出。如果是栈存储九可能存在有fd节点不会被处理的可能。

 

 

list存储准备就绪的io,当内核准备就绪的时候,会执行epoll_event_callback的回调函数,将epitem添加到list当中,当epoll_wait激活重新运行的时候会将list的epitem注意拷贝到ecents参数中。

Rbtree 用来存储所有 io 的数据,方便快速通 io_fd 查找。也从 insert remove 来讨论。
对于 rbtree 何时添加:当 App 执行 epoll_ctl EPOLL_CTL_ADD 操作,将 epitem 添加到 rbtree
中。何时删除呢?当 App 执行 epoll_ctl EPOLL_CTL_DEL 操作,将 epitem 添加到 rbtree 中。

 2. Epoll 的线程安全,SMP 的运行,以及防止死锁

 epoll在一些操作上是需要加锁保护。

list操作 rbtree操作    epoll_wait的等待操作。

list操作较为简单,只有简单的几行。所以采用力度较小的(spinlock)自旋锁,方便再添加操作的时候能够快速的操作list。

 红黑树采用的互斥锁

三、 Epoll 回调

当讨论到epool回调则需要和协议栈一起用

1.tcp三次握手完成之后  

对端反馈 ack 后, socket 进入 rcvd 状态。需要将监听 socket
event 置为 EPOLLIN ,此时标识可以进入到 accept 读取 socket 数据
2  内核协议栈recvbuffer有数据的时候  收到数据以后,需要将 socket event 置为 EPOLLIN 状态。
··
3 内核协议栈send有空闲的时候 
检测 socket send 状态,如果对端 cwnd>0 是可以,发送的数据。故需要将 socket
置为 EPOLLOUT
4  tcp四次挥手的收到fin数据的时候
established 状态,收到 fin 时,此时 socket 进入到 close_wait 。需要 socket event
置为 EPOLLIN 。读取断开信息。
所以在四处添加epoll的回调函数,即可是的epoll正常接收到数据,就可以使epoll正常的接收到IO事件。

 四、 LT ET

LT(水平触发)  ET(边沿触发)

比如: event = EPOLLIN | EPOLLLT ,将 event 设置为 EPOLLIN 与水平触发。只要 event EPOLLIN
时就能不断调用 epoll 回调函数。
比如 : event = EPOLLIN | EPOLLET event 如果从 EPOLLOUT 变化为 EPOLLIN 的时候,就会触
发。在此情形下,变化只发生一次,故只调用一次 epoll 回调函数。关于水平触发与边沿触
发放在 epoll 回调函数执行的时候,如果为 EPOLLET (边沿触发),与之前的 event 对比,如
果发生改变则调用 epoll 回调函数,如果为 EPOLLLT (水平触发),则查看 event 是否为 EPOLLIN
即可调用 epoll 回调函数。
再简化一点   LT:只要内核协议栈recvbuffer 有数据就会不停的触发epoll函数。
ET是只要满足recvbuffer从无到有,九触发回调函数,而且只回调一次.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值