1. 概念:
I/O多路转接技术, 是先构造一张有关描述符的列表, 然后调用一个函数, 直到这些描述符中的一个已准备好进行I/O时, 该函数才返回. 在返回时, 它告诉进程哪些描述符已经准备好可以进行I/O.
在Linux下poll, pselect, select这三个函数都可以执行I/O多路转接操作, 今天我们主要说select函数.
2. select函数:
#include
<
sys
/
select.h
>
int select( int maxfdp1, fd_set * restrict readfds, fd_set * restrict writefds, fd_set * restrict exceptfds,
struct timeval * restrict tvptr);
正常则返回准备就绪的描述符数, 超时则返回0, 出错则返回 - 1 .
int select( int maxfdp1, fd_set * restrict readfds, fd_set * restrict writefds, fd_set * restrict exceptfds,
struct timeval * restrict tvptr);
正常则返回准备就绪的描述符数, 超时则返回0, 出错则返回 - 1 .
下面对参数进行说明:
- maxfdp1: MAX File Description Plus 1. 最大描述符+1.
- tvptr: 等待时间, 用一个timeval结构的值表示, 有3种情况:
- tvptr == NULL: 永远等待. 可被信号中断.
- tvptr->tv_sec == 0 && tvptr->tv_usec == 0: 完全不等待, 测试所有指定的描述符并立即返回. 非阻塞轮询.
- tvptr->tv_sec != 0 &7 tvptr->tv_usec != 0: 等待指定的时间数. 时间超过立即返回0. 可被信号中断.
- readfds, writefds, exceptfds: 指向描述符集的指针, 分别是可读, 可写, 异常的描述符. 每个描述符集存放在一个fd_set数据类型中.
fd_set可进行以下3种处理:
- 分配一个这种类型的变量.
- 将这种类型的一个变量赋值给同类型的另一个变量.
- 其他处理.
关于其他处理, 由以下几个宏来实现:
#include
<
sys
/
select.h
>
/* 判断fd是否在描述符集fdset中 */
int FD_ISSET( int fd, fd_set * fdset);
在则返回非0, 不在则返回0.
/* 判断fd是否在描述符集fdset中 */
int FD_ISSET( int fd, fd_set * fdset);
在则返回非0, 不在则返回0.
#include
<
sys
/
select.h
>
/* 将一指定位清楚 */
void FD_CLR( int fd, fd_set * fdset);
/* 设置fd_set变量的一个指定位为fd */
void FD_SET( int fd, fd_set * fdset);
/* 将fdset的所有位设置为0 */
void FD_ZERO(fd_set * fdset);
/* 将一指定位清楚 */
void FD_CLR( int fd, fd_set * fdset);
/* 设置fd_set变量的一个指定位为fd */
void FD_SET( int fd, fd_set * fdset);
/* 将fdset的所有位设置为0 */
void FD_ZERO(fd_set * fdset);
3. 说明:
前面我们所说的"准备好", 具体地说是指:
- 若对读集(readfds)中的一个描述符的read操作将不会阻塞, 则此描述符是准备好的.
- 若对写集(writefds)中的一个描述符的write操作将不会阻塞, 则此描述符是准备好的.
- 若异常状态集(exceptfds)中的一个描述符有一个未决异常状态, 则此描述符是准备好的. 现在, 异常状态包括:
- 在网络连接上到达的带外数据.
- 在处于数据包模式的伪终端上发生了某些状态.
描述符的阻塞是否并不影响select的阻塞. 也就是说, 这是两种阻塞层关系, 比如: 读一个非阻塞描述符, 并且以超时值5s调用select, 则select最多阻塞5s. 又比如: 指定一个tvptr = NULL 来调用select, 则该描述符数据准备好或捕捉到一个信号之前, select是一直阻塞的.
4. pselect:
POSIX.1 定义了一个select的变体, 即: pselect, 对于这个函数不多介绍, 只说一下和select的两点区别:
- 超时结构, select用timeval, pselect用const timespec. 这使得时间更精确, 并且不会被修改.
- pselect可使用一可选择的信号屏蔽字sigmask. 在调用pselect时, 以原子操作的方式安装该信号屏蔽字, 在返回时恢复以前的信号屏蔽字.
5. 实例:
编写中, 等待添加...