之前已经把网络 I/O 相关要点都盘了,还剩 select/poll/epoll 这几个区别没说,这篇就来搞搞它们,并且是从完全理解原理的角度来区分它们。
本来是要上源码的,但是感觉没啥必要,身为应用开发者我觉得理解原理就行了,源码反正看了就忘了,理解才是最重要!所以我就尽量避免代码且用大白话来盘一盘这三个玩意。
话不多说,发车。
小思考
首先,我们知道 select/poll/epoll 是用来实现多路复用的,即一个线程利用它们即可 hold 诸多个 socket。
按照这个思路,线程不可能被任何一个被管理的 Socket 阻塞,且任一个 Socket 来数据之后都得告知 select/poll/epoll 线程。
想想看,这应该如何实现呢?
我们拿 select 的逻辑来分析下
按照我们的理解,select 管理多个 Socket 的模型如下图所示:

这里要注意一下内核态和用户态的交互,用户程序访问不了内核空间。
所以,我们调用 select 会把所有要管理的 socket 的 fd (文件描述符,Linux下皆为文件,简单理解就是通过 fd 能找到这个 socket)传到内核中。
此时,要遍历所有 socket,看看是否有感兴趣的事件发生。如果没有一个 socket 有事件发生,那么 select 一上线程就需要让出 cpu 阻塞等待,这个等待可以是不设置超时时间的死等,也可以是设置 timeout 的有超时时间的等待。
假设此时客户端发送了数据,网卡接收到的数据塞到对应的 socket 的接收队列中,此时 socket 知道来数据了,那如何唤醒 select 呢?
其实每个 socket 有个属于自己的睡眠队列,select

本文详细解析了select、poll和epoll在网络I/O多路复用中的工作原理,探讨了它们的优缺点。通过分析select的内核睡眠队列和回调机制,介绍了poll如何优化fds结构,以及epoll如何通过内核维护socket集合和ready_list避免无效遍历,同时提及了epoll的ET和LT模式及其应用场景。
最低0.47元/天 解锁文章
2956





