linux select函数详解
在 Linux中,我们可以使用 select函数实现 IO端口的复用,传递给 select函数的参数会告诉内核:
1. 我们所关心的文件描述符 (即某一个 Socket) - Linux中,socket也是以文件形式存在,即一切资源皆文件
2. 对于每个描述符,我们所关心的状态
3.我们要等待多长时间
从 select函数返回后,内核告诉我们一些信息:
1. 根据我们的要求已经做好准备的描述符的个数
2. 对于三种条件 (即调用 select时所传递的参数)哪些描述符已经做好了准备:读、写、异常
有了这些描述符,我们就可以去调用合适的 IO函数 (通常是 read / write),实现一些非阻塞的操作 - 如:对于的读缓冲区已经有了数据,,
linux select函数接口:
#include <sys/select.h>
int select(int maxfdp1, fd_set readset, fd_set writeset, fd_set exceptset,struct timeval timeout);
返回:我们所关心的已就绪的描述符个数
maxfpd1 - 最大有效位的个数
...set:fd_set其实是 bitMap结构,里面存放着我们所关心的某事件就绪的描述符集合,其实就是以 "位图"的形式进行保存
首先我们先看一下最后一个参数。它指明我们要等待的时间:
struct timeval {
long tv_sec; /*秒 */
long tv_usec; /*微秒 */
}
C++中使用 select函数的 demo:
经上所述:select存在的问题有哪些呢?
① select函数中,我们会去将刚兴趣的描述符对应事件集合传递进去,这里实际上涉及到了用户态到内核态数据的拷贝,内核在操作时会去修改此集合,返回的时该集合实际上表述的便是已经发生对应事件就绪的描述符,但此集合实际上是以位图形式存在的,用户态就需要去逐位进行判断,以此知晓对应事件是否已发生,这实际上是低效的做法
② 由①知,由于 select函数中已经去修改了对应的用户感兴趣的描述符事件集合,因此 对应的 set便得不到复用,因此在每个循环中,都会去手动去重新初始化下 set,这也是低效的
③ 由②知,每次自旋去调用 select时,都会进行一次数据的拷贝,这是低效的
④ 对应的 fd_set是 bitMap结构,位长 1024,即最多也只能去监听 1024个描述符事件,性能得不到很好的发挥...