现在的位置: 首页 > 综合 > 正文

I/O多路转接—-select调用

2019年04月24日 ⁄ 综合 ⁄ 共 1691字 ⁄ 字号 评论关闭

select() 系统调用提供一个机制来实现同步多元I/O:

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select (int n,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout);

FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);

调用select() 将阻塞,直到指定的文件描述符准备好执行I/O,或者可选参数timeout指定的时间已经 过去。

监视的文件描述符分为三类set,每一种对应等待不同的事件。readfds中列出的文件描述符被监视是否有数据可供读取(如果读取操作完成则不会阻 塞)。writefds中列出的文件描述符则被监视是否写入操作完成而不阻塞。最后,exceptfds中列出的文件描述符则被监视是否发生异常,或者无 法控制的数据是否可用(这些状态仅仅应用于套接字)。

这三类set可以是NULL,这种情况下select()不监视这一类事件。

select()成功返回时,每组set都被修改以使它只包含准备好I/O的文件描述符。例如,假设有两个文件描述 符,值分别是7和9,被放在readfds中。当select()返回时,如果7仍然在set中,则这个文件描述符已经准备好被读取而不会 阻塞。如果9已经不在set中,则读取它将可能会阻塞(我说可能是因为数据可能正好在select返回后就可用,这种情况下,下一次调用select()将返回文件描述符准备好读取。

第一个参数n,等于所有set中最大的那个文件描述符的值加1。实际上是要检查的描述符数。

timeout参数是一个指向timeval结构体的指针,timeval定义如下:

#include <sys/time.h>
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* 10E-6 second */
};

如果这个参数不是NULL,则即使没有文件描述符准备好I/O,select()也会在经过tv_sec秒和 tv_usec微秒后返回。当select()返回时,timeout参数的状态在不同的系统中是未定义的,因此每次调用select() 之前必须重新初始化timeout和文件描述符set。实际上,当前版本的Linux会自动修改timeout参数,设置它的值为剩余时间。因此,如果 timeout被设置为5秒,然后在文件描述符准备好之前经过了3秒,则这一次调用select()返回时tv_sec将变为2。

如果timeout中的两个值都设置为0,则调用select()将立即返回,这是轮询系统找到多个描述符状态而不阻塞select函数的方法。

文件描述符set不会直接操作,一般使用几个助手宏来管理。这允许Unix系统以自己喜欢的方式来实现文件描述符set。但大多数系统都简单地实现set 为位数组。

FD_ZERO移除指定set中的所有文件描述符。每一次调用select()之前都应该先调用它。

FD_SET添加一个文件描述符到指定的set中,FD_CLR则从指定的set中移除一个文件描述符。

FD_ISSET测试一个文件描述符是否指定set的一部分。如果文件描述符在set中则返回一个非0整数,不在则返回0。FD_ISSET在调用select() 返回之后使用,测试指定的文件描述符是否准备好相关动作

因为文件描述符set是静态创建的,它们对文件描述符的最大数目强加了一个限制, 能够放进set中的最大文件描述符的值由FD_SETSIZE指定。在Linux中,这个值是1024。

select() 成功时返回准备好I/O的文件描述符数目,包括所有三个set。如果提供了timeout,返回值可 能是0;错误时返回-1。

POSIX。1也定义了一个 select 变体,称为 pselect。详情可参考其手册页。

抱歉!评论已关闭.