// 6. 事件循环
    struct epoll_event events[MAX_EVENTS];
    while (true) {
        // 等待事件发生
        int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (nfds < 0) {
            perror("epoll_wait failed");
            break;
        }

epoll 事件循环(服务器的「心脏」)

这是epoll 高并发服务器最核心的死循环,服务器99%的时间都在这里运行

整段代码的作用(大白话)

// 开辟一个数组,用来存放【触发了事件的socket】
struct epoll_event events[MAX_EVENTS];

// 死循环:永远运行,等待客户端连接/发数据
while (true) {
    // 阻塞等待:只要有事件来,就立刻返回
    int nfds = epoll_wait(...);

    // 出错处理
}

一句话:这是服务器的「永动心跳」,负责等待并接收所有客户端事件。


逐行深度拆解

1. 定义事件数组

struct epoll_event events[MAX_EVENTS];

作用:

创建一个「事件结果数组」

  • MAX_EVENTS:你自己定义的最大同时处理事件数(比如 100、1024、4096)
  • eventsepoll_wait 会把所有触发的事件填到这个数组里

类比:

这是一个**“事件托盘”**
epoll 检测到哪些 socket 有动静,就把它们放到这个托盘里给你。


2. 服务器主循环

while (true) {

作用:

无限循环

  • 服务器必须 24 小时不停运行
  • 处理完一批事件 → 立刻回去继续等待下一批
  • 这就是服务器不退出、一直服务的原因

3. 核心函数:epoll_wait(等待事件)

int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);

这是 epoll 最重要的函数!

作用:阻塞等待,直到有事件发生,然后返回事件数量。

四个参数逐行解释(必须背会)

参数 含义 解释
epoll_fd epoll 实例 你创建的监控器
events 事件数组 内核把触发的事件填到这里
MAX_EVENTS 最大事件数 一次最多返回多少个事件
-1 超时时间 -1 = 永久阻塞,直到有事件

重点:timeout = -1 是什么意思?

  • -1永久阻塞
    没有事件 → 程序休眠,不占CPU
    有事件 → 立刻唤醒返回

  • >0:等待 N 毫秒超时

  • 0:不等待,直接返回(轮询)

服务器一般都用 -1,高效节能。


返回值 nfds 是什么?

nfds = number of file descriptors ready
意思:本次有多少个 socket 触发了事件

例如:

  • nfds = 1 → 1 个客户端连接/发来了数据
  • nfds = 5 → 5 个 socket 同时有事件

4. 错误判断

if (nfds < 0) {
    perror("epoll_wait failed");
    break;
}
  • 成功:返回 ≥0
  • 失败:返回 -1
  • 常见错误:被信号中断、epoll_fd 失效

底层原理(超级通俗)

把 epoll 看作 保安室

  1. epoll_wait = 保安坐在椅子上等动静
  2. 没有事件 → 保安睡觉(不占CPU)
  3. 有客户端连接/发消息 → 内核立刻叫醒保安
  4. 保安把所有事件放到 events 托盘里
  5. 返回 nfds:告诉你来了几个事件

执行流程(一看就懂)

  1. 进入循环
  2. 调用 epoll_wait阻塞休眠
  3. 客户端发来连接/数据
  4. 内核自动通知 epoll
  5. epoll_wait 醒来,返回事件数
  6. 接下来就是遍历 events 数组处理事件

极简总结(超好记)

  1. events[MAX_EVENTS]:存放触发事件的托盘
  2. while(true):服务器永不退出
  3. epoll_wait:阻塞等待事件(连接/数据)
  4. nfds:返回有多少个socket需要处理
  5. timeout=-1:永久等待,节能高效

接下来要做什么?(你代码的下一段)

// 遍历所有触发的事件
for (int i = 0; i < nfds; i++) {
    // 1. 如果是监听套接字 → 有新客户端连接
    if (events[i].data.fd == listen_sockfd) {
        // accept 接收连接
        // 把新客户端加入 epoll 监控
    }
    // 2. 如果是普通客户端 → 有数据来了
    else {
        // read 读取数据
        // 处理业务逻辑
    }
}

这就是 epoll 服务器完整逻辑


一句话总结

epoll_wait 是服务器的心脏,每一次跳动,都在处理客户端的连接与消息!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐