select,poll,epoll

1、select函数

select函数的原型

select的函数原型
int select (int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout)

重要参数:

fdset是一个集合,这个集合里面放的是文件描述符(文件句柄)。fdset的部分宏如下

fd_set set;
FD_ZERO(&set)//将set清零
FD_SET(fd, & set)//将fd放入set
FD_CLR(fd, & set)//将fd从set中清零
FD_ISSET(fd, & set)//如果在fd在set中则为真

timeval是一个常用的结构,用来代表时间值,有两个成员,一个是秒数,一个是毫秒数

截下来说一下select的参数描述

(1)maxfdp是一个整数值,用来代指集合中所有文件描述符的范围(所有文件描述符最大值+1)
(2)readfds是只想fd_set的一个指针。因为要监视文件描述符的读变化;
如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读;
如果没有可读的文件,则根据timeout参数再判断是否超时;如果超过timeout的时间,select返回0;若发生错误返回负值,也可以传入NULL,代表不关心任何可读文件 (
3)writefds跟readfds类似,是一个关心可写文件描述符的文件描述符; 这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可读;如果没有可写的文件,则根据timeout参数再判断是否超时;
如果超过timeout的时间,select返回0;若发生错误返回负值,也可以传入NULL,代表不关心任何可写文件 (
4)timeout是select的超时时间,这个参数至关重要,特可以是select处于3种状态:
1、若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;
2、若将时间值设为0,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;
3、timeout的值大于0,这就是等待超时的时间,select在timeout时间内阻塞,超时时间之内有事情到来就返回了,否则在超市后不管怎么样一定返回,返回值如上 (5);返回准备就绪的描述符数,若超时啧返回0,错误返回-1

2、poll函数

poll函数原型

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域中返回。具体时间代码如下

实际上这些时间在events域中毫无意义,因为他们都会在适合的时候在revents中返回

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

POLLIN|POLLPRI等于select的读事件,POLLOUT|POLLWRBAND等价于select()的写事件

POLLIN等价于POLLRDNORM|POLLRDBAND,而POLLOUT则等价于POLLIN|POLLOUT。

 

timeout参数指定等待的毫秒数,无论IO是否准备好,poll都会返回。timeout指定为负数值时表示无限超时

使poll()一直挂起直到一个指定事件发生;timeout为0指示poll调用立即返回并列出准备好IO的描述符,但并不等待其他的事件

这种情况下,poll()的返回值,一旦被选举出来,立即返回。

poll成功时,结构体中revents域不为0的的文件描述符个数;如果在超时前没有任何事件发生,poll返回0

失败时,poll返回-1,并设置error

 

3、epoll函数

使用epoll必须使用下面这个头文件
#include<sys/epoll.h>

epoll操作过程需要3个接口,如下
int epoll_create(int size)
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event)
int epoll_wait(int epfd,struct epoll_event *event,int maxevent,int timeout)

下面介绍一下这三个机口的功能、入参和出参的含义

int epoll_create(int size)

创建一个epoll的句柄,size是用来告诉内核要监听的数目。这个参数不同于select的第一个参数,是最大监听的fd+1的值

需要注意的是,创建好epoll句柄后,他就会占用一个fd值(使用完epoll后,要使用close()关闭)

 

int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event)

这个接口是epoll的事件注册函数,它不同于select()在监听事件时告诉内核要监听什么类型的时间,而是先注册要监听的事件类型

第一个参数是epoll_create()的返回值,第二个参数表示三个动作

(1)EPOLL_CTL_ADD,注册新的fd导epfd中 (2)EPOLL_CTL_MOD,修改已经注册的fd时间(3)EPOLL_CTL_DEL,删除一个已经注册的fd事件

第三个参数是需要监听的fd

第四个参数是告诉内核需要监听什么样的事件,struct epoll_event结构如下

struct epoll_event{
    _uint32_t events;
    epoll_data_t data;      
}

event包括以下几个宏:

(1)EPOLLIN,表示对应的文件描述符可以读(包括对端SOCKET正常关闭)

(2)EPOLLOUT,表示对应的文件描述符可以写

(3)EPOLLPRI,表示对应的文件描述符有紧急数据可读(这里应该表示有带歪的数据到来)

(4)EPOLLERR,表示对应的文件描述符发生错误

(5)EPOLLHUP,表示对应的文件描述符被挂断

(6)EPOLLET,将EPOLL设置为ET模式

(7)EPOLLONESHOT,之监听一次事件,如果这次之后还要监听则需要将这个SOCKET加入到EPOLL队列中

 

int epoll_wait(int epfd,stuct epoll_event *event,int maxevents,int timeout)

等待时间的产生,类似于selcet()的调用,参数events用来从内核得到事件的集合,maxevents告诉内核这个events有多大,且

maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(ms为单位,0会立即返回,01将不确定或永久阻塞)

该函数返回需要处理的事件数目,如果返回0代表超时

posted @ 2019-03-22 19:54  阿十三  阅读(152)  评论(0编辑  收藏  举报