一、select
1.函数原型
函数原型
#include<sys/select.h>
select(int maxfdpl,
fd_set *restrict readfds,fd_set *restrict writefds,fd_set*restrict exceptfds,
struct timeval *restrict tvptr
);
//maxfdpl:最大文件描述符编号值加1.可以设定为FD_SETSIZE,指定最大描述符数(经常是1024),大多数程序只使用3~10个描述符
//中间三个参数是指向描述符的指针,每个描述符集存储在fd_set数据类型中。
//对于fd_set数据类型,唯一可以进行的处理是:分配一个这种类型的变量,将这种类型的一个变量值给·同类型的一个变量,或者可以使用以下四个函数中的一个:
#include<sys/select.h>
FD_ISSET(int fd,fd_set *fdset);//测试fdset描述符集中的fd是否打开(比如可读、可写)
FD_CLR(int fd,fd_set *fdset);//清除fd
FD_SET(int fd,fd_set *fdset);//开启fd
FD_ZERO(fd_set *fdset);//将fd_set集中的所有变量清0
//tvptr
//tvptr==NULL,永远等待;
//tvptr->tv_sec==0&&tvptr->tvusec==0,根本不等嗲;
//tvptr->tv_sec!=0||tv->tv_usec!=0,等待指定的秒数和微秒数.
返回值:
-1:出错
0:没有描述符准备好
正返回值:已经准备好的描述符数
注:如果在一个描述符碰见了文件尾端,select会认为该描述符是可读的
2. 使用步骤
使用步骤
fd_set rset;//声明一个描述符集
int fd;//描述符
FD_ZERO(&rset);//将声明的描述符集清0
FD_SET(fd,rset);
FD_SET(SUDIN_FILENO,rset);
//从select返回时,可以用FD_ISSET测试该集中的一个给定位是否仍处于打开状态
if(FD_ISSET(fd,&rset)){
...
}
二、poll
1. 函数原型
参考:epoll使用详解:epoll_create、epoll_ctl、epoll_wait、close
#include<poll.h>
int poll(struct pollfd fdarray[],nfds_t nfds,int timeout);//返回值:准备就绪的描述符数目,若超时,返回0,如出错,返回-1
struct pollfd{
int fd;//文件描述符
short events;//对文件描述符感兴趣的事件
shor revents;//发生在fd上的事件
}
//fdarray数组中的元素由nfds指定
//timeout==-1 在 <stropts.h>定义为INFTIM;
//timeout==0,不等待;
//timeout>0,等待timeout毫秒
使用select和poll可以实现异步形式的通知,关于描述符的状态,系统并不告诉我们描述符的状态,我们需要进行查询。
三、epoll
1. 函数原型
int epoll_create(int size);//创建一个epool对象,在epoll文件系统中给这个句柄分配资源
int epoll_ctl(int epfd,int op,int fd,struct epollevent *event);//想epoll对象中添加套接字
int epoll-wait();//收集发生事件的连接
2. 详解
- epoll_create()
当函数调用epoll_create方法时,linux内核会创建一个eventpoll结构体,这个结构体里面由两个成员与epoll的使用方式密切相关。
struct eventpoll{
//红黑树的根节点,这颗树中存储着所有添加到epoll的事件
//也就是epoll监控的事件
stuct rb_root rbr;
//双向链表rdllist,保存着将要通过epoll_wait返回给用户的,满足条件的事件
struct list_head rdllist;
}
解析:
我们调用epoll_create时,内核会帮我们在epoll文件系统里建立一个file结点,在内核cache里建立一个红黑树存储以后epoll_ctl传来的socket,建立一个rdllist双向链表用于存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个rdllist双向链表即可,所以epoll非常高效。
rdllist如何得到事件:所有添加到epoll的事件都会与设备驱动程序建立回调关系,也就是说相应的事件发生时会调用这个回调方法,这个回调方法在内核中叫做ep_poll_callback,这个回调方法会把事件放到rdllist双向链表中。
epoll的LT模式(水平触发)和ET模式(边缘触发):LT,只要有数据就会返回。ET,只有数据到来才会触发。