多个请求复用了一个进程,这就是多路复用
我们熟悉的 select/poll/epoll 内核提供给用户态的多路复用系统调用,进程可以通过一个系统调用函数从内核中获取多个事件。
select/poll/epoll 是如何获取网络事件的呢?在获取事件时,先把所有连接(文件描述符)传给内核,再由内核返回产生了事件的连接,然后在用户态中再处理这些连接对应的请求即可。
select/poll/epoll 这是三个多路复用接口,都能实现 C10K 吗?****
select 实现多路复用的方式是:将已连接的 Socket 都放到一个文件描述符集合,然后调用 select 函数将文件描述符集合拷贝到内核里,让内核来检查是否有网络事件产生,检查的方式很粗暴,就是通过遍历文件描述符集合的方式,当检查到有事件产生后,将此 Socket 标记为可读或可写, 接着再把整个文件描述符集合拷贝回用户态里,然后用户态还需要再通过遍历的方法找到可读或可写的 Socket,然后再对其处理。
select.select()函数的阻塞底层
一个好看理解的视频:https://vdn6.vzuu.com/SD/349279b4-9119-11eb-85d0-1278b449b310.mp4?pkey=AAV4N4IDIVwRUk_F_gPymLmVb9_gEkMUaDSituI-Efezf68FqldIafrlJN5shyLPS7z4klKxNO2msP5m9ixPjRdu&c=avc.0.0&f=mp4&pu=078babd7&bu=078babd7&expiration=1702303197&v=ks6
存在的问题:
cat /proc/sys/fs/file-max
察看。32位机默认1024个,64位默认2048。poll主要针对第2点问题进行改进。
select 使用固定长度的 BitsMap,表示文件描述符集合,而且所支持的文件描述符的个数是有限制的,在 Linux 系统中,由内核中的 FD_SETSIZE 限制, 默认最大值为 1024
,只能监听 0~1023 的文件描述符。
poll 不再用 BitsMap 来存储所关注的文件描述符,取而代之用动态数组,以链表形式来组织,突破了 select 的文件描述符个数限制,当然还会受到系统文件描述符限制。
// select 存储
// 开一个长度为8的byte数组,当我要监听第0、3个socket应该这样标记
// 10010000
// poll存储
// 0->3
// 现在假如第三个socket有了事件
// select 返回 00010000
// poll 返回 0->1