本文来自个人博客:https://dunkwan.cn
I/O多路转接
函数select
和pselect
在所有POSIX兼容的平台上,select
函数时我们可以执行I/O多路转接。传给select
的参数告诉内核:
- 我们关心的描述符
- 对于每个描述符我们所关心的条件
- 愿意等待多长时间
从select
返回时,内核告诉我们:
- 已准备好的描述符总数
- 对于读、写或异常这3个条件中每一个,哪些描述符已准备好
#include <sys/select.h>
int select(int maxfdpl, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds, struct timeval *restrict tvptr);
返回值:准备就绪的描述符数目;若超时,返回0;若出错,返回-1。
tvptr
参数指定愿意等待的时间长度。分为以下三种情况:
tvptr == NULL
永远等待。如果捕捉到一个信号则中断此无限期等待。当所指定的描述符中的一个已准备好或捕捉到一个信号则返回。如果捕捉到一个信号,则
select
返回-1,errno
设置为EINTR
。
tvptr->tv_sec == 0 && tvptr->tv_usec == 0
根本不等待。测试所有的指定的描述符并立即返回。这是轮询系统找到多个描述符状态而不阻塞的
select
函数的方法。
tvptr->tv_sec != 0 || tvptr->tv_usec != 0
等待指定的秒数和微秒数。当指定的描述符之一已准备好,或当指定的时间值已经超过时立即返回。如果在超时到期时还没有一个描述符准备好,则返回值是0。与第一种情况一样,这种等待可被捕捉到的信号中断。
readfds
、writefds
和exceptfds
参数是分别指向我们关心的可读、可写和处于异常条件的描述符集合。我们可以将这三个参数中的每一个都视为一个很大的字节数组。
对于fd_set
数据类型的可以进行的处理是:分配一个这种类型的变量,将这种类型的一个变量赋给同类型的另一个变量,或对这种类型的变量使用以下4个函数中的一个。
#include <sys/select.h>
int FD_ISSET(int fd, fd_set *fdset);
返回值:若fd在描述符集中,返回非0值;否则,返回0。
void FD_CLR(int fd, fd_set *fdset);
void FD_SET(int fd, fd_set *fdset);
void FD_ZERO(fd_set *fdset);
FD_ISSET
:测试描述符集中的某一个指定位是否打开
FD_SET
:开启描述符集中的一位
FD_CLR
:清除一位
FD_ZERO
:将一个fd_set
变量的所有位设置为0
POSIX.1还定义了一个pselect
函数,该函数是select
的一个变体。
#include <sys/select.h>
int pselect(int maxfdpl, fd_set *restrict readfds, fd_set *restrict exceptfds, const struct timespec *restrict tsptr, const sigset_t *restrict sigmask);
返回值:准备就绪的描述符数目;若超时,返回0;若出错,返回-1。
除了以下几点外,pselect
和select
相同。
select
的超时值用timeval
结构相同,但pselect
使用timespec
结构。pselect
的超时值被声明为const
,这保证了调用pselect
不会改变此值。pselect
可使用可选信号屏蔽字。sigmask
为NULL
,那么在与信号有关的方面,pselect
的运行状况和select
相同。否则,sigmask
指向一信号屏蔽字,在调用pselect
时,以原子操作的方式安装该信号屏蔽字。在返回时,恢复以前的信号屏蔽字。
函数poll
poll
函数可用于任何类型的文件描述符。
#include <poll.h>
int poll(struct pollfd fdarray[], nfds_t nfds, int timeout);
返回值:准备就绪的描述符数目;若超时,返回0;若出错,返回-1。
poll
函数第一个参数是由pollfd
数组构成,这个数组中的每个元素指定一个描述符编号以及对该描述符感兴趣的条件。以下是该结构体。
struct pollfd{
int fd; /* file descriptor to check, or < 0 to ignore */
short events; /* events of interest on fd */
short revents; /* events that occurred on fd */
};
fdarray
数组的元素个数由nfds
指定。
events
可设置为下图中的一个或多个,这些值告诉内核我们关心的是每个描述符的哪些事件。返回时,revents
由内核设置,用于说明每个描述符发生了哪些事件。
timeout
参数3种不同情形。
timeout == -1
永远等待。当所指定的描述符中的一个已准备好,或捕捉到一个信号时返回,如果捕捉到一个信号,则
poll
返回-1,errno
设置为EINTR
。
timeout == 0
不等待。测试所有描述符并立即返回。这是一种轮询系统的方法,可以找到多个描述符的状态而不阻塞
poll
函数。
timeout > 0
等待
timeout
毫秒。当指定的描述符之一已准备好,或timeout
到期时立即返回。如果timeout
到期时还没有一个描述符准备好,则返回值是0。