在I/O复用中,epoll的性能就比select和poll要更好了,但是epoll仅Linux独有
epoll有三个接口
-
int epoll_create(int size);
创建一个epoll内核事件表(记录文件描述符和事件类型),底层是一颗红黑树,size象征性的给一个大小,但是具体并不由size限制,知识提示内核大概需要这么大 -
int epoll_ctl(int epfd, int op, struct epoll_event * event);
操作内核事件表,op操作对应插入EPOLL_CTL_ADD;修改EPOLL_CTL_MOD;删除EPOLL_CTL_DEL。epoll_event内的events记录事件类型,内的data中的fd记录文件描述符(类型不止这两种,其他这里用不到,不做说明) -
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)
这里的events是一个数组,这个数组由内核填充,maxevents为最大长度,timeout时间限制
返回值为就绪的文件个数,且全部填充至events中
从接口以及结构中可以看出,epoll同poll一样,监听的文件描述符个数以及范围不受限制,且事件类型更多,它具有poll相同的优点,但是比poll更加优秀,他的记录方式由内核自行维护一个事件表,不需要传入,只需要操作这个事件表的文件描述符即可,而且返回后数组中的文件描述符都是就绪的,不需要进行检测,内核检测就绪的方式是回调
- int listenfd = CreateSock();//返回监听套接字
- int epfd = epoll_create()//创建内核事件表
- epoll_ctl(,EPOLL_CTL_ADD,listenfd,)//监听套接字插入
操作的宏只是在poll的宏前加“E” - while(1)//进入循环
- epoll_events[MAXEVENT]//创建接收就绪事件文件描述符的数组,MAXEVENT为最大大小
- n = epoll_wait(epfd,events,MAXEVENT,-1)//检测就绪,就绪的文件描述符传入events中,返回值为n,代表就绪的个数
- DealReadyfds(epfd,events,n,listenfd)//注意我们在epoll中,传入的个数不再是数组长度,而是就绪个数,因为events中填充的都是就绪的,所以我们传入就绪个数即可
if(当前是监听套接字)//获取新连接
if(EPOLLRDHUP)//断开事件,close当前
if(EPOLLIN)//读数据,recv/send
检测就绪文件时间复杂度为O(1)