📡【Network】select的一些疑问?
最大只能监听1024个fd?
- 为什么是 1024?:
- 历史原因:早期 Unix 系统的设计选择了这个值作为平衡性能和内存消耗的折中方案。
- 硬编码限制:
FD_SETSIZE在编译时固定,无法在运行时动态调整。
- 绕过限制的尝试:
- 虽然可以通过修改
FD_SETSIZE宏并重新编译内核或程序来增加限制,但这可能引发兼容性问题(例如与其他库的交互)。
- 虽然可以通过修改
如果ReadSet中fd的长度已经是1024,那么WriteSet的长度是否只能为0?
关键结论:
select的三个 fd_set(读、写、异常)的容量限制是相互独立的,不会因为一个集合满了而影响另一个集合。详细解释:
select的 fd_set 结构:
tempReadSet可以监控 fd0~1023,同时tempWriteSet也可以监控另一组 fd0~1023(允许重叠)。nfds参数的作用:
nfds是三个集合中 最大的 fd 值 + 1,用于限制内核检查的范围。- 即使某个集合中有 1024 个 fd,只要它们的值较小(例如
0~10),nfds可以远小于 1024,从而提升效率。注意事项:
- fd 值的限制:
select要求所有监听的 fd 值必须< FD_SETSIZE(即 0~1023)。如果程序使用了更大的 fd(如 2000),即使只监听一个也会失败。- 性能问题:
- 即使三个集合各自未满,
select仍需线性扫描所有 fd(时间复杂度 O(n)),在超高并发时效率远低于epoll(O(1))。
如果Select唤醒后,可读fd 事件有两个,那为什么第一个fd可读时没有立刻唤醒?
select 是“水平触发”(Level-Triggered,LT)的,它的唤醒机制是批量通知,而非逐个通知。
select是否立刻唤醒?- 是,只要
select正在监听且 fd 就绪,内核会尽快唤醒它(除非被调度延迟)。
- 是,只要
- 为什么有时会一次性返回多个就绪 fd,而不是逐个唤醒?
select是 批量通知机制,它会在一个调用周期内返回所有就绪的 fd,而不是逐个触发。- 如果多个 fd 的数据几乎同时到达,
select会合并通知,提高效率。如何避免“漏事件”?
- `select` 是 **水平触发(LT)** 的,只要数据未被读完,下次调用 `select` 时仍然会返回该 fd。 - 确保在 `select` 返回后 **完整处理所有就绪的 fd**,避免遗漏。
何为“同一次监听周期内”?这个监听周期的时长是多久?
1. 什么是“监听周期”?
在 select 的上下文中,“监听周期” 指的是从 select 开始阻塞等待 到 被唤醒返回 的这段时间。
在这段时间内,内核会持续检查被监听的 fd,直到至少一个 fd 就绪、超时或发生信号中断。
- 监听周期 ≈
select的一次完整调用过程(从进入内核到返回用户态)。 - 它不是固定的时间长度,而是动态的,取决于事件发生的时机。
2. 监听周期的“时长”是多久?
监听周期的时长由以下因素决定:
- 是否有 fd 就绪:
- 如果有 fd 就绪(例如数据到达),
select会立刻唤醒,周期可能极短(微秒级)。
- 如果有 fd 就绪(例如数据到达),
- 是否设置了超时(
timeout): - 是否被信号中断:
3. 为什么“同一次监听周期内”的事件会合并通知?
- 内核的优化机制:
当select阻塞时,内核不会为每个就绪的 fd 立即唤醒进程,而是会短暂等待,看看是否有其他 fd 也在同一时间段就绪。如果有,则合并通知,减少上下文切换的开销。- 例如:
fd1和fd2的数据包几乎同时到达,内核可能在一次中断处理中发现它们都就绪,然后统一唤醒select。
- 例如:
- 无严格时间界限:
“同一次监听周期”没有固定的时间窗口(如 1ms 或 10ms),而是取决于:- 内核调度策略(如 Linux 的
epoll/select实现细节)。 - 硬件中断处理的延迟(如网卡收到数据后触发中断的时机)。
4. 对比
select和epoll的监听周期
- 内核调度策略(如 Linux 的
| 特性 | select | epoll(LT 模式) |
| ——— | ————— | —————- |
| 监听周期 | 单次调用内批量检查所有 fd | 基于事件回调,无需全量遍历 |
| 事件合并 | 可能合并同周期内的就绪 fd | 可精确控制(ET 模式时更严格) |
| 时间复杂度 | O(n)(每次遍历所有 fd) | O(1)(仅返回就绪 fd) |
| 适用场景 | fd 数量少(<1024) | 高并发(万级 fd) |
总结
- 监听周期是
select从调用到返回的时间段,无固定时长,取决于事件和超时。 - 同周期内的事件可能合并通知,这是内核的优化策略,为了减少唤醒次数。
- 如需更精确的事件控制,建议切换到
epoll(ET 模式)或调整timeout。
相关笔记
- select和epoll
- 套接字读写