select系统调用是用来让我们的程序监视多个文件句柄的状态变化的,程序会在这里等待,一直到被监视的文件句柄发生了改变(可以是一个也可以是多个)
select函数原型
#include
int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout)
//nfds: 需要监视的最大文件描述符值+1,为了减少内核中的遍历次数
//readfds: 可读文件描述符的集合
//writefds:可写文件描述符的集合
//exceptfds:异常文件描述符的集合
//timeout: 这个参数有三种
//1.NULL:表示select()没有timeout,select将一直阻塞,直到某个文件描述符发生事件再返回
//2.0:检测描述符集合的状态,然后立即返回,并不等待外部事件的发生
//3.特定的时间值:如果在指定的时间段里没有描述符就绪发生,select将超时返回
//返回值:返回值<0表示监控出错,返回值=0表示没有描述符就绪,返回值>0,表示就绪的描述符个数
fd_set结构
这个结构实际上是一个位图,用位图中的为表示需要监控的文件描述符,并且提供了一组操作fd_set的接口
void FD_CLR(int fd,fd_set *set);//清除描述词组set中相关fd的位
int FD_ISSET(int fd,fd_Set *set);//测试描述词组set中相关fd的位是否为真
void FD_SET(int fd,fd_set *set);//设置描述词组set中相关fd的位
void FD_ZERO(fd_set *set);//清除描述词组set的全部位
select使用流程:
select中的集合:fd_set结构体,结构体中只有一个成员,就是一个数组,这个数组用来做位图
描述符是一个数字,添加描述符就是这个数字对应的比特位置为1,表示此描述符被添加到集合中
select最多可以监控多少描述符:取决于宏_FD_SETSIZE,默认1024
select优缺点分析
优点
缺点
poll解决了select的文件描述符上限的问题,然后相较于select做了一些优化,模型差不多
poll函数模型
int poll(struct pollfd *fds,nfds_t nfds,int timeout);
//fds:要监控的描述符事件结构体,nfds:实际上第一个参数描述符事件的结构体数量,timeout:超时等待时间(ms)
//fds结构体
struct pollfd{
int fd;//要监控的描述符
short events;//描述符想要监控的事件,按位操作,是一个监控指定事件的标志位
short revents;//实际就绪的事件
}
//events:POLLIN:可读,POLLOUT:可写
//revents:当poll接口调用返回时,这个描述符实际就绪的事件就会写入revents中,可以通过此成员进行判断就绪的描述符
//返回值:返回值>0表示就绪的描述符个数,返回值=0表示监控超时,返回值<0表示监控出错
poll使用流程
struct pollfd fds[10];
fds[0].fd = 0;//标准监控输入
fds[0].events = POLLIN | POLLOUT;//对标准输入监控可读事件以及可写事件
int poll(struct pollfd *fds,nfds_t nfds,int timeout);
poll优缺点
优点
epoll是Linux下性能最高的多路转接模型
根据man手册,epoll是在poll的基础上,为了实现处理大批量操作句柄而在poll的基础上改进的
epoll流程
int epoll_create(int size);
//size: 要监控的描述符最大数量,在linux2.6.8后被忽略,不再有最大数量限制,大于0即可
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
//epfd:epoll操作句柄()epoll_create()的返回值)
//op: 取值有三个
//EPOLL_CTL_ADD:添加新的描述符到epfd
//EPOLL_CTL_MOD:修改注册的描述符的监听事件
//EPOLL_CTL_DEL:从epfd中删除一个描述符
//fd:epoll操作句柄,需要监听的fd
//event:监控描述符对应的事件结构体信息
struct epoll_event{
uint32_t events;//表示要监控的事件,以及监控调用返回后实际就绪的事件(EPOLLIN/EPOLLOUT)
union epoll_data{
int fd;//描述符
void* ptr;//当ptr中包含描述符时,可以直接操作
}data;
}
int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);
//epfd:epoll的操作句柄,通过这个句柄找到内核中指定的eventpoll结构
//events:epoll_event描述符的事件结构体数组的首地址,用于获取就绪的描述符对应的事件结构体,不能为空指针
//maxevents:events数组的节点数量,主要为了防止就绪太多,向events中放置的时候越界访问
//timeout:超时等待时间,单位为ms,-1表示永久阻塞,0则立即返回
//返回值:大于0表示就绪的描述符个数,等于0表示等待超时,小于0表示监控出错
epoll监控原理
epoll优缺点
优点
epoll的事件触发模式
水平触发(默认触发方式):EPOLLLT(select和poll只有这种触发方式)
触发方式
边缘触发:需要在epoll_event结构体中的events成员设置EPOLLET,有新数据到来会触发事件
水平触发和边缘触发那个好?
根据不同场景使用不同的触发方式