socket 多路 IO 复用之 select 模型

select 模型是 socket 中的一种多路 IO 复用模型之一,通过轮询的方式来完成多路访问控制。

一个很简单的例子来描述 select 模型:

幼儿园老师要照顾所有的小朋友,每天他都会轮流去问小朋友:「小朋友小朋友,你饿了吗?」

如果小朋友饿了,那么老师就给这个小朋友喂饭,否则就开始询问下一个朋友,一直循环下去直到放学。

同时,如果班级里有其他的同学来了,也把他加到询问队列。如果有哪个同学生病了,则把它踢出询问队列。

select 模型的原理就是这样,把所有连接的客户端 socket 加入到一个集合中去,然后一直不断轮询,判断哪一个 socket 有数据到达,就读取数据。否则继续轮询下一个数据。

linux 系统在编译的时候就固定了 select 模型文件描述符集合的大小为 1024 个,这个大小无法更改,因此,select 模型只适用于并发量小于 1024 个的服务连接。

一、相关函数

select 用来判断文件描述符结合中是否有文件描述符发生了相应的事件,如果有事件则返回 (这个策略可以改变) 。

参数说明:

nfds: 监控的文件描述符集里最大文件描述符加 1,因为此参数会告诉内核检测前多少个文件描述符的状态。

readfds:监控有读数据到达文件描述符集合,传入传出参数。

writefds:监控写数据到达文件描述符集合,传入传出参数。

exceptfds:监控异常发生达文件描述符集合, 如带外数据到达异常,传入传出参数。

timeout:定时阻塞监控时间,3 种情况:1.NULL,永远等下去;2. 设置 timeval,等待固定时间;3. 设置 timeval 里时间均为 0,检查描述字后立即返回

返回值: 文件描述符集合中有响应时间的文件描述符个数。

超时类型的结构体:

对监控描述符集合的操作:

通常情况下,我们需要一个客户端数组保存每一个客户端的状态,表示当前集合中的该元素是否已经有存在或者连接。然后还要有一个最大的文件描述符标志,用来轮询。

一旦 select 返回,我们要先判断是否为服务端的 socket,如果是服务端的,说明有新的连接加入,把这个新连接加入到集合中去。否则则说明是客户端连接有响应,这时候需要一个一个去循环判断,看哪个 socket 有数据到达,然后处理。

二、示例代码

发表评论