📊 第 3 章 · select 详解

fd_set 位图原理 · 内核工作流程 · 1024 上限触底体验

① fd_set 位图可视化(FD_SET / FD_CLR / FD_ISSET)

下方是一个 1024 位的位图(这里只画前 256 位),点击任意 bit 切换状态,或在输入框里输入 fd 编号操作。每个 bit 对应一个 fd——这就是 select 监听集合的本质。

未关心 FD_SET(关心) 就绪(select 返回后)
→ 当前位图状态会显示在这里

② select 一次调用的内核内部流程

每次 select 调用涉及 5 个步骤——把整个 fd_set 来回拷贝、O(n) 加入等待队列、O(n) 检查就绪。这就是它慢的真相。

点击「播放」观察内核到底做了什么

🧑 用户态(你的程序)

① 准备 fd_set: FD_SET(3); FD_SET(5); FD_SET(8)
② 调 select(9, &rfds, NULL, NULL, NULL)
③ select 返回,rfds 已被改写
④ 遍历 0~max_fd, FD_ISSET 找就绪
⑤ 对就绪的 fd 调用 read

🛡️ 内核态

① 把 fd_set 从用户拷到内核 [O(n)]
② 遍历 fd_set, 把当前进程加到每个 fd 的等待队列 [O(n)]
③ 进程睡眠 💤 等任一 fd 唤醒
④ 某 fd 来数据 → 唤醒进程
⑤ 再遍历一遍 fd_set, 把就绪的 bit 写回 [O(n)]
⑥ 把改写后的 fd_set 拷回用户态 [O(n)]
→ 点击播放

③ FD_SETSIZE = 1024 触底体验

输入一个 fd 编号,看 FD_SET 是合法还是越界。1024 是编译期硬上限——这就是 poll 和 epoll 出现的关键诱因。

0
0 ⚠️ 1024(FD_SETSIZE) 2000+
→ 输入 fd 编号试试看