依赖的头文件
/* According to POSIX.1-2001, POSIX.1-2008 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
方法定义
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);
特征
select() and pselect() allow a program to monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g., input possible). A file descriptor is considered ready if it is possible to perform a corresponding I/O operation (e.g., read(2) without blocking, or a sufficiently small write(2)).
select和pselect方法可以监听多个fd,直到其中的一个或多个准备好可以进行读取或写入操作。
select() can monitor only file descriptors numbers that are less than FD_SETSIZE; poll(2) does not have this limitation.
select只可以同时监听最多FD_SETSIZE个文件描述法,而poll则没有最大限制。
The operation of select() and pselect() is identical, other than these three differences:
(i) select() uses a timeout that is a struct timeval (with seconds and microseconds), while pselect() uses a struct timespec (with seconds and nanoseconds).
(ii) select() may update the timeout argument to indicate how much time was left. pselect() does not change this argument.
(iii) select() has no sigmask argument, and behaves as pselect called with NULL sigmask.
select和pselect的区别主要有三点:
1)select使用了timeval类型的timeout(单位为秒和毫秒),pselect使用的是timespec(单位是秒和纳秒)
2)select可以更新timeout的值而pselect不可以
3)select没有sigmask参数,与pselect使用值为NULL的sigmask的参数时效果相同
参数解释
Three independent sets of file descriptors are watched. The file
descriptors listed in readfds will be watched to see if characters
become available for reading (more precisely, to see if a read will
not block; in particular, a file descriptor is also ready on end-of-
file). The file descriptors in writefds will be watched to see if
space is available for write (though a large write may still block).
The file descriptors in exceptfds will be watched for exceptional
conditions.
三个独立的文件描述符集合被监听,其中readfds中的fd被监听是否可读,writefds被监听是否可写,exceptfds被监听是否有异常状态。
On exit, each of the file descriptor sets is modified in place to
indicate which file descriptors actually changed status. (Thus, if
using select() within a loop, the sets must be reinitialized before
each call.)
当函数退出时,每个fd集合都可能被修改,因此当在循环中使用select函数时,要记得每次重新初始化fd 集合。
Four macros are provided to manipulate the sets. FD_ZERO() clears a
set. FD_SET() and FD_CLR() respectively add and remove a given file
descriptor from a set. FD_ISSET() tests to see if a file descriptor
is part of the set; this is useful after select() returns.
四个宏命令可以用来操作这些fd集合:
FD_ZERO()用来清空fd集合;
FD_SET()和FD_CLR()分别用来向fd集合添加和删除一个fd;
FD_ISSET()用来查看一个fd是否属于某一个fd集合,该方法通常在select返回后使用。
nfds should be set to the highest-numbered file descriptor in any of
the three sets, plus 1. The indicated file descriptors in each set
are checked, up to this limit
nfds参数应该被设置成三个fd集合的数量最大值加一,这样每个fd集合中的fd都可以被check一次。我理解是FD_ISSET宏会根据这个值去遍历每个fd集合。
The timeout argument specifies the interval that select() should
block waiting for a file descriptor to become ready. The call will
block until either:
- a file descriptor becomes ready;
- the call is interrupted by a signal handler; or
- the timeout expires.
If both fields of the timeval structure are zero, then select()
returns immediately. (This is useful for polling.) If timeout
is NULL (no timeout), select() can block indefinitely.
timeout参数用来设置select阻塞的时间,直到其中一个fd可以进行读写,或者中断,或者超时。如果timeout设为0则select会立刻返回(轮询时很有用),设为NULL则select函数会一直阻塞下去。
sigmask is a pointer to a signal mask (see sigprocmask(2)); if it is
not NULL, then pselect() first replaces the current signal mask by
the one pointed to by sigmask, then does the "select" function, and
then restores the original signal mask.
错误类型
EBADF An invalid file descriptor was given in one of the sets.
(Perhaps a file descriptor that was already closed, or one on
which an error has occurred.) However, see BUGS.
EINTR A signal was caught; see signal(7).
EINVAL nfds is negative or exceeds the RLIMIT_NOFILE resource limit
(see getrlimit(2)).
EINVAL The value contained within timeout is invalid.
ENOMEM Unable to allocate memory for internal tables.
返回值
On success, select() and pselect() return the number of file
descriptors contained in the three returned descriptor sets (that is,
the total number of bits that are set in readfds, writefds,
exceptfds) which may be zero if the timeout expires before anything
interesting happens. On error, -1 is returned, and errno is set to
indicate the error; the file descriptor sets are unmodified, and
timeout becomes undefined.
select执行成功时,会返回三个fd集合的fd总数量。超时时返回值为0。发生错误时返回-1,可以通过errno的值查看报错信息。
代码示例
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 5;
tv.tv_usec = 0;
retval = select(1, &rfds, NULL, NULL, &tv);
/* Don‘t rely on the value of tv now! */
if (retval == -1)
perror("select()");
else if (retval)
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) will be true. */
else
printf("No data within five seconds.\n");
exit(EXIT_SUCCESS);
}