epoll原理简介

348 阅读2分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。

说起 epoll,我们需要先提一下同步阻塞的网络 io 模型。

什么是同步阻塞模型?服务器接收到一个网络请求,会依次采用如下流程进行处理:

  1. 创建 socket,等待接收数据,将进程 id 放入 socket 等待队列中
  2. 数据包抵达网卡
  3. 网卡把数据DMA到内存
  4. 网卡硬中断通知 cpu
  5. cpu 发出软中断给 ksoftirqd 内核进程进行处理
  6. ksoftirqd 内核进程从内存 ringbuffer 摘下数据包送到1创建的 socket 队列中,唤醒 socket 等待队列中的进程进行处理
  7. socket 进行后续处理

它有如下几个缺点:

  • 一个连接占用一个进程,并发的情况下需要启用大量进程,消耗资源;
  • 没有数据/数据没到的情况下需要将cpu的控制权交出,即需要频繁切换进程,消耗资源;

从上面可以看到,一个进程只处理一个连接,那么有没有一个进程可处理多个连接的方法?有,epoll就是其中一个。方法就是当有一个连接有数据到来,能第一时间知道。

与epoll相关的函数有三个:

  • epoll_create: 创建 epoll 对象
  • epoll_ctl: 向 epoll 中添加连接
  • epoll_wait: 等待连接上的 io 事件

详细来说,流程如下:

  1. 创建 epoll 对象,epoll 对象主要由就绪队列、socket 红黑树、等待队列等组成
  2. 添加 socket 到 epoll 对象中
  3. 检查就绪队列,如果队列为空,就阻塞住,然后把 cpu 的控制权交给其它进程
  4. 如果有数据到达,那么 cpu 触发软中断,那么将 socket 送入到 epoll 的就绪队列
  5. 唤醒用户进程,检查就绪队列,通过红黑树查找到数据所属的 socket,并进程处理

可以看到,epoll 非常高效,可以实现一个进程监听多个连接,所以在网络服务器中有非常广泛的应用。