select

Linux内核、Windows内核都提供了select 操作,可以把1024个文件描述符的IO事件轮询,简化为一次轮询,轮询发生在内核空间。
image.png
image.png

使用select的核心步骤

  • 先准备了一个数组fds,让fds存放着所有需要监视的socket.
  • 然后调用select, 如果fds中的所有socket 都没有数据,select 会阻塞,直到有一个socket 接收到数据, select返回,唤醒进程。
  • 用户可以遍历fds, 通过FD ISSET 判断具体哪个socket 收到数据,然后做出处理。

image.png
image.png
image.png

对于调用了select的进程A而言:
1. A存在于多个socket的等待队列中
2.当某个socket被写入数据时,A也被唤醒并从多个socket的等待队列中移除后加入内核的工作队列
3.但是此时A并不知道是哪个socket被写入了数据,所以只能遍历所有socket
4.在A处理完任务后移出内核的工作队列,但是此时却需要遍历所有socket加入它们的等待队列中
**

select的不足:

两次socket列表遍历:

  • 第1次: 每次调用select都需要将fds列表传递给内核,有一定的开销。进程加入socket的等待队列时,需要遍历所有socket。
  • 第2次: 当进程A被唤醒后,进程只知道至少有一个socket接收了数据,不知道是谁。程序需遍历一遍socket列表,才可以得到就绪的socket。唤醒后需要从等待队列中移除。

:::tips 正是因为遍历操作开销大,出于效率的考量,才会规定select的最大监视数量,默认只能监视1024个socket。 :::