2.1.8 epoll的实现原理
一、epoll使用背景
1.1 epoll能做什么?
答:epoll可以通过单线程模式实现用户态的协议栈。
1.2 为什么要实现用户态的协议栈?内核协议栈很稳定,不是用的挺好的吗?
答:每一帧数据从网卡接收完,到达应用程序需要2次的数据迁移,第一次是从网卡copy协议栈,第二次是从协议栈copy到应用程序。如果把协议栈做到用户空间(范围包括原本的协议栈部分和应用程序部分),这样数据只需要从网卡copy到用户空间就可以了,可以减少一次copy的耗时,减少内核协议栈调用recv()send()的等函数的切换,因此用户态的协议栈实现高性能网络,比如C10M的实现(C10M 是 "Concurrency 10 Million"(并发 1000 万)的缩写,通常用来描述一个系统或应用程序的并发连接能力。通过户态的协议栈)。
1.3 epoll不也是属于内核吗?
答:epoll 确实是内核提供的接口,用来高效地监听和管理大量并发连接的 I/O 操作,但它只是帮助用户程序管理 I/O 事件通知,而真正的网络协议栈逻辑(如 TCP/IP 堆栈处理)仍然是在内核中。如果协议栈在用户态,那么 epoll 配合用户态协议栈,能在完全用户态环境下处理数据传输,从而避免了内核的切换和大量不必要的系统调用。
1.4 自定义构建epoll类的函数,需要对epoll原理了解后才能方便构建。
二、epoll数据结构
2.1 构成epoll的2个结构体?
答: eventpoll和epiem,分别由epoll_create()和epoll_ctl(EPOLL_CTL_ADD)创建。
2.2 epoll数据结构和数据的插入和删除?
答:eventpoll中 List 用来存储准备就绪的IO (fd),红黑树 用来存储所有io 的数据 (事件),方便快速通io_fd 查找。
何时将数据插入到list 中?何时从list里删除?调用 epoll_wait 后,内核将 list 中的 epitem 拷贝到用户传入的 events 参数,并清空 list。
rbtree 何时添加:当App 执行epoll_ctl EPOLL_CTL_ADD 操作,将epitem 添加到rbtree中。何时删除呢?当App 执行epoll_ctl EPOLL_CTL_DEL 操作,将epitem 添加到rbtree 中
总的顺序来说:
- 调用
epoll_ctl
注册。 - 等待事件就绪。
- 内核触发
epoll_event_callback
。 - 用户调用
epoll_wait
处理事件。
2.3 一次只能设置一个监听事件?
答:一个调用只能操作一个文件描述符,不能对多个 fd 同时执行(需循环处理)。但对一个 fd,可以一次设置多个事件,通过事件掩码完成。