select
select是跨平台的。
一、复用
- 复用的意思时不用每个进程/线程来操控单独的一个IO,只需一个进程/线程来操控多个IO;
- 内核空间不能直接解引用用户态的指针;
- 非阻塞IO。
二、select说明
- 一般用connect、accept、recv或recvfrom这类函数,程序阻塞,直至该套接字上接受到数据后程序才能继续运行。
- 但是使用select函数可以实现非阻塞方式的程序。它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。
- 每次进行select调用都会线性扫描全部的fd集合。这样,效率就会呈现线性下降。
- 内核/用户空间内存拷贝问题:select在解决将fd消息传递给用户空间时采用了内存拷贝的方式,处理效率不高
select是无差别轮询。
函数原型
1 | int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval*timeout); |
两个结构体
struct fd_set
- 可以理解为一个集合,这个集合中存放的是文件描述符(filedescriptor),即文件句柄,这可以是我们所说的普通意义的文件;
fd_set
集合可以通过一些宏由人为来操作
1 | //清空集合 |
struct timeval
1 | struct timeval |
函数参数
int maxfdp
是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1。
fd_set * readfds
- 是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化;
- 如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读
- 如果没有可读的文件,则根据timeout参数再判断是否超时;
- 若超出timeout的时间,select返回0;
- 若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。
fd_set * writefds
同上,监视文件写变化。
fd_set * errorfds
同上,监视文件错误异常。
struct timeval * timeout
- 若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;
- 若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;
- timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。
返回值
- 负值:select错误
- 0:等待超时,没有可读写或错误的文件
- 正值:某些文件可读写或出错
三、伪代码
1 | socket...; |