Unix环境变量--I/O多路复用

本文深入解析Linux下的IO复用技术,包括select、pselect、poll和epoll的使用方法与特性。详细介绍了各函数的参数、返回值及注意事项,对比了它们之间的差异,特别是poll和epoll在处理大量并发连接时的优势。

在linux下,实现IO复用的系统调用主要有三个:select、pselect、poll 和 epoll,下面我们将对其进行逐一讲解。

一、函数select及函数pselect

注意事项:(1)一个描述符阻塞与否不影响select是否阻塞。

(2)如果在一个描述符上遇到了文件末尾,select认为它是可读的。也就是说,到达文件末尾时,select并不会给一个异常提示

(3)如果调用成功,此时所有参数都会被重置为0,所以需要重新赋值

int select(int nfds,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout);

头文件:#include <sys/select.h>   #include <sys/time.h>

参数:nfds:监听的文件描述符的集合中的最大文件描述符加1

readset:读事件集合     writeset:写事件集合  exceptset:异常事件集合(若对某些事件不关心,则可以置为NULL)

timeval:等待时间,(1)为NULL则表示无限等待 (2)时间为0则表示不等待(3)其他为等待的时间长

返回值:-1:出错,测试文件描述符集合都不会被更改

0:表示没有描述符准备好,此时,所有描述符集都会被置0。

其他正数:一个正的返回值表明已经准备好的描述符数。该值是3个描述符集中准备好的描述符数之和

 

上述中的参数中的集合,通过以下方式进行赋值:

void FD_ZERO(fd_set *fdset); //清空集合

void FD_SET(int fd, fd_set *fdset); //将一个给定的文件描述符加入集合之中

void FD_CLR(int fd, fd_set *fdset); //将一个给定的文件描述符从集合中删除

int FD_ISSET(int fd, fd_set *fdset); // 检查集合中指定的文件描述符是否可以读写

除了select外,POSIX提供一个select的变体:

 int pselect(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds,fd_set *restrict exceptfds, const struct timespec *restrict tsptrconst sigset_t *restrict sigmask);

头文件:#include <sys/select.h>

返回值:准备就绪的描述符数目;若超时,则返回0;若出错,返回-1

pselect和select几乎相同,除了以下两点: 

(1)pselect的超时值使用timespec结构,该结构以秒和纳秒表示超时值,能够提供更精确的超时时间。 pselect的超时值被声明为const,这保证了超时值不会在调用时被修改。 (2)pselect使用可选的信号屏蔽字。如果参数sigmask非空,则在函数被调用时,以原子的方式安装该屏蔽字,再返回时,恢复以前的屏蔽字。


二、函数poll

  poll的机制与select类似,与select在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制

# include <poll.h>

int poll ( struct pollfd * fds, unsigned int nfds, int timeout);

pollfd结构体定义如下:

struct pollfd {

int fd;         /* 文件描述符 */

short events;         /* 等待的事件 */

short revents;       /* 实际发生了的事件 */

} ;

 每一个pollfd结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示poll()监视多个文件描述符。每个结构体的events域是监视该文件描述符的事件掩码,由用户来设置这个域。revents域是文件描述符的操作结果事件掩码,内核在调用返回时设置这个域。events域中请求的任何事件都可能在revents域中返回。合法的事件如下:

      POLLIN         有数据可读。

  POLLRDNORM       有普通数据可读。

  POLLRDBAND      有优先数据可读。

  POLLPRI         有紧迫数据可读。

  POLLOUT            写数据不会导致阻塞。

  POLLWRNORM       写普通数据不会导致阻塞。

  POLLWRBAND        写优先数据不会导致阻塞。

  POLLMSGSIGPOLL     消息可用。

此外,revents域中还可能返回下列事件:

       POLLER     指定的文件描述符发生错误。

  POLLHUP   指定的文件描述符挂起事件。

  POLLNVAL  指定的文件描述符非法。

这些事件在events域中无意义,因为它们在合适的时候总是会从revents中返回。

使用poll()和select()不一样,你不需要显式地请求异常情况报告。

POLLIN | POLLPRI等价于select()的读事件,POLLOUT |POLLWRBAND等价于select()的写事件。POLLIN等价于POLLRDNORM |POLLRDBAND,而POLLOUT则等价于POLLWRNORM。例如,要同时监视一个文件描述符是否可读和可写,我们可以设置 events为POLLIN |POLLOUT。在poll返回时,我们可以检查revents中的标志,对应于文件描述符请求的events结构体。如果POLLIN事件被设置,则文件描述符可以被读取而不阻塞。如果POLLOUT被设置,则文件描述符可以写入而不导致阻塞。这些标志并不是互斥的:它们可能被同时设置,表示这个文件描述符的读取和写入操作都会正常返回而不阻塞。

  timeout参数指定等待的毫秒数,无论I/O是否准备好,poll都会返回。timeout指定为负数值表示无限超时,使poll()一直挂起直到一个指定事件发生;timeout为0指示poll调用立即返回并列出准备好I/O的文件描述符,但并不等待其它的事件。这种情况下,poll()就像它的名字那样,一旦选举出来,立即返回。

返回值和错误代码

成功时,poll()返回结构体中revents域不为0的文件描述符个数;如果在超时前没有任何事件发生,poll()返回0;失败时,poll()返回-1,并设置errno为下列值之一:

       EBADF         一个或多个结构体中指定的文件描述符无效。

  EFAULTfds   指针指向的地址超出进程的地址空间。

  EINTR      请求的事件之前产生一个信号,调用可以重新发起。

  EINVALnfds  参数超出PLIMIT_NOFILE值。

  ENOMEM       可用内存不足,无法完成请求。

三、epoll函数

epoll函数的讲解建议参考:https://blog.youkuaiyun.com/qq_36359022/article/details/81355897

https://blog.youkuaiyun.com/daaikuaichuan/article/details/83862311

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chiang木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值