apue I/O多路转接,select与poll

I/O多路转接

select

传向select的参数告诉内核:

  • 我们所关心的描述符。
  • 对于每个描述符,我们所关心的状态(是否读一个给定的描述符?是否写一个给定的描述符?是否关心一个描述符的异常状态?)。
  • 愿意等待多长时间(可以永远等待,等待一个固定量时间,或完全不等待)。

从select返回时,内核告诉我们:

  • 已经准备好的描述符的数量。
  • 对于读、写或异常这三个状态中的每一个,哪些描述符已经准备好。
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
返回值:准备就绪的文件描述符数,若超时则返回0,若出错则返回-1.

先说明最后一个参数,它指定愿意等待的时间:

struct timeval {
    long tv_sec; // 秒
    long tv_usec; // 微妙
};

有三种情况:

  1. timeout==NULL,永远等待。当所指定的文件描述符中的一个已准备好或捕捉到一个信号则返回。如果捕捉到一个信号,则select返回-1,errno设置为EINTR。
  2. timeout->tv_sec==0 && timeout->tv_usec==0,完全不等待。
  3. timeout->tv_sec!=0 || timeout->tv_usec != 0,等待指定的秒数和微妙数。当指定的描述符之一已准备好,或当指定的时间已经超过时立即返回,超时时返回0。与第一种情况一样,这种等待也可能被信号中断。

中间的三个参数readfds、writefds和exceptfds是指向描述符集的指针。这三个描述符集说明了我们关心的可读、可写或处于异常条件的各个描述符。描述符集使用fd_set类型表示。
对fd_set类型可以进行的处理是:分配一个这种类型的变量;将这种类型的一个变量值赋予同类型的另一个变量;或对于这种类型的变量使用下列四个函数。

#include <sys/select.h>
// 判断fd是否在set中
int  FD_ISSET(int fd, fd_set *set);
    返回值:若fd在描述符集中则返回非0值,否则返回0// 将fd添加到set集合中
void FD_SET(int fd, fd_set *set);
// 将fd从set中移除
void FD_CLR(int fd, fd_set *set);
// 将set清零
void FD_ZERO(fd_set *set);

中间参数中的任意一个或全部都可以是空指针,这表示对应的状态并不关心。如果三个指针都是空指针,那么select提供了比sleep更精确的定时器。

select的第一个参数nfds需要传入“最大的描述符加1”。在三个描述符集中,找出最大的描述符值,然后加1。

select的变体pselect:

#include <sys/select.h>
/**
* @param  nfds      最大描述符加1
* @param  readfds  读描述符集
* @param  writefds  写描述符集
* @param  exceptfds 异常描述符集
* @param  timeout  超时时间
* @param  sigmask  信号屏蔽字
* @return          准备就绪的描述符个数,若超时则返回0,失败返回-1
*/
int pselect(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, const struct timespec *timeout,
                  const sigset_t *sigmask);

除了一下几点,pselect和select相同:

  • select的超时值用timeval定义,pselect的超时值使用timespec定义。timespec使用秒和纳秒表示超时值。pselect的超时值为const。
  • pselect可以指定信号屏蔽字。在调用pselect时原子的安装信号屏蔽字,在返回时,恢复以前的信号屏蔽字。

poll

poll函数类似于select,poll的定义如下:

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout)

与select不同,poll不是每个状态(可读性、可写性和异常状态)构造一个描述符集,而是统一的放在pollfd数组中,每个数组元素指定一个描述符以及对其关心的状态。

struct pollfd {
    int fd; // 描述符
    short events; // 对该描述符的哪些事件感兴趣
    short revents; // 该描述符哪些事件发生了
};

nfds说明数组fds的长度。
events可以设置为下面表格中的值。函数返回时,内核设置revents成员,说明在该描述符上发生了哪些事件。
这里写图片描述
表14-6中,头四行测试可读性,接着三行测试可写性,最后三行测试异常状态。最后三行是由内核在返回时设置的。即使在events中没有指定这三个值,如果相应条件发生了,在revents中仍然会设置它们。
当一个描述符被挂断(POLLHUP)后,就不能再写该描述符。但是仍可从该描述符读取数据。
poll的最后一个参数说明我们愿意等待的时间,与select一样,有三种情况:
1. timeout == -1,永远等待。当所指定的描述符中有一个准备好或则捕捉到一个信号时返回。
2. timeout == 0,不等待。测试所有描述符并立即返回。
3. timeout > 0,等待timeout毫秒。当指定的描述符之一准备好,或指定的时间超时时立即返回。超时返回0。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值