## 引言:从“阻塞”的餐厅到“事件驱动”的盛宴
想象一下,你是一家小餐馆的服务员。餐厅只有5张桌子。你的工作流程是这样的:走到1号桌,问他们是否要点菜,然后站在那里等他们决定;等他们点完,再去2号桌,同样站在那里等... 如果1号桌的客人看菜单看了半个小时,那么其他桌的客人就会饿肚子,甚至愤然离场。
这种“一个接一个,必须等前一个完成才能服务下一个”的模式,就是典型的 **阻塞 I/O**。在网络编程中,如果一个服务器用这种方式处理连接(`accept`)和读写(`read`, `write`),那它的并发能力将极其低下,只能服务极少数客户端。
再想象一家更高级的餐厅。你,作为服务员,不再傻站在一桌旁等待。你的流程变成了:首先巡视全场,依次询问每一桌:“您好,现在需要点菜吗?”“菜好了,请慢用。”“需要加菜吗?”。如果某桌客人说“我们还没想好”,你就先跳过他们,去问下一桌。等巡视完一圈,你又从头开始新一轮的询问。
这种“一次性收集所有客户需求,然后统一处理”的模式,就是 **I/O 多路复用** 的核心思想。你(服务器进程)就像一个高效的经理,同时“监视”着多个客人(文件描述符),谁准备好了(可读/可写/异常)就处理谁,而不是被任何一个客人阻塞住。
在 Linux 中,实现这种“高效巡视”的经典方法就是 `select` 和 `poll`。本文将带你深入实战,彻底掌握它们。
---
## 第一部分:内核的监视器 - Select
### 1.1 Select 的工作原理
`select` 系统调用允许进程指示内核等待多个文件描述符中的任何一个变为“就绪”状态(如可读、可写或发生异常),或者经历一段指定的时间后返回。