epoll是能实现同时多个用户访问的效率最高的IO多路复用技术;
与poll相比,它不在限制监听描述;只返回就绪的fd时间复杂度变低了·;
不用轮询所有的fd;只拷贝一次fd,在内核维护一颗红黑树保存所有监听fd;
两种触发方式:LT/ET(LT是默认触发方式)
用程序实现epoll
框架
cs
//服务端
socket(listenfd)
bind
listen
//创建epoll对象
//int epoll_create(int size);
功能:就是创建一个epoll对象,在内核中,开辟一个空间,用来保存要监听的所有文件描述符;
参数:@size:就是预估要监听多少个fd;现在只需要大于0就行
返回值:成功返回非负整数,就是epoll文件描述符epfd;失败赶回-1并且设置errno;
int epfd = epoll_create(5);
if(epfd<0){perror("epoll_create faill");return -1;}
//添加要关心的fd(epoll_ctl,因为是添加,一般这里写成函数就行;当然它也有删除,修改epfd)
//int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event)
功能:对epoll实例做增加、修改、删除监听的文件描述符fd;把fd注册到内核红黑树;设置要监听什么事件;
参数:epfd:就是epoll_create返回的epfd;
op:对fd想要进行的操作;从三个宏中根据需求选一个(EPOLL_CTL_ADD(增加),(EPOLL_CTL_MOD(修改),(EPOLL_CTL_DEL(删除))
fd:要监听的文件描述符;比如客户端的clifd,服务端这里就监听listenfd;
event:可以完成两个任务;一个是想监听什么事件(EPOLLIN------有数据发过来)(EPOLLOUT------可以发数据)(EPOLLET------边缘触发;默认是水平触发);另一个就是保存一下这个fd的编号,后面epoll_wait拿到数据就知道是哪个fd就绪了
返回值:成功返回0;失败返回-1;
int epoll_add(int epfd,int fd)
{
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = fd;
}
if(epoll_ctl(epfd,EPOLL_CTR_ADD,fd,&ev) <0)
if(epfd<0){perror("epoll_ctl faill");return -1;}
epoll_add(epfd,listenfd);
while(1)
{
//epoll_wait(int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
功能:当有fd事件就绪;他就会把时间记录在event数组里;如果没有就阻塞等待;
参数:epfd:epoll_create的返回值
events:就是用来记录监听的fd中哪个事件就绪了;
maxevents:监听事件的最大值;
timeout:等待超时时间,单位毫秒(-1------永久阻塞;0------非阻塞;>0等待指定毫秒)
返回值:成功返回就绪时间的个数;失败返回-1;
struct epoll_event rev[2];
bzero(rev;sizeof(rev));
int ret = epoll_wait(epfd,rev,2,-1);
if(epfd<0){perror("epoll_ctl faill");return -1;}
int i = 0;
for(i=0;i<ret;++i)
{
if(rev[i].data.fd == listenfd)
{
connfd =accept;
}
}else
{
//通信过程
}
}