i、支持一个进程打开大数目的socket描述符;
select()所支持打开的FD是有一定限制,FD_SETSIZE默认值是1024/2048。epoll没有描述符数量限制,一般是1G内存可以有10万左右,可通过使用cat /proc/sys/fs/file-max查看。
ii、IO效率不随FD数目增加面线性下降;
select/poll每次调用都会线性扫描全部的集合(同时还会轮询),导致效率呈现线性下降。而epoll不存在这个问题,因为epoll会为每个描述符FD注册一个回调函数,只有“活跃”的socket才会主动调用callback函数,其他idle状态socket则不会。当调用callback函数的FD,才返回相应的事件。
iii、使用mmap加速内核与用户空间的消息传递;
select、poll、epoll都需要内核把fd消息通知给用户空间。而epoll通过内核与用户空间mmap处于同一块内存实现消息的传递。
epoll_create函数
#include
int epoll_create(int size);//告诉内核监听fd的数目
//返回一个epoll句柄epfd,后续均要用着,在使用完epoll后,必须调用close关闭epfd,否则可能导致fd被耗尽
epoll_ctl事件注册函数
#include
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
struct epoll_event {
_uint32_t event;//Epoll events
epoll_data_t data;//User data variable
};
typedef union epoll_data {
void* ptr;
int fd;
uint32_t u32;
uint64_t u64;
}epoll_data_t;
此函数先要注册要监听的事件类型(如listenfd);
第一个参数是epoll_create()的返回值;
第二个参数表示动作,用3个宏来表示:
1、EPOLL_CTL_ADD,注册新的fd到epfd中;
2、EPOLL_CTL_MOD,修改已经注册的fd的监听事件;
3、EPOLL_CTL_DEL,从epfd中删除一个fd;
第三个参数是需要监听的fd
第四个参数 告诉内核需要监听什么事,其中struct epoll_event结构体中的events可以是以下几个宏的集合,EPOLLIN(表示对应文件描述符可以读(包括对端socket正常关闭)),EPOLLOUT(表示对应文件描述符可以写),EPOLLPRI(表示对应文件描述符有紧急的数据可读),EPOLLERR(表示对应文件描述符发生错误),EPOLLHUP(表示对应文件描述符被挂断),EPOLLET(将EPOLL设为边缘触发模式,这是相对水平触发而言),EPOLLONESHOT(只监听一次事件,当监听完这次事件后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里)。
epoll_wait等待事件发生函数
#include
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);//等待事件的发生
//返回需要处理的事件数目,返回0表示已超时
参数events(结构数组)用来从内核得到事件的集合,maxevents告诉内核这个events有多大,且maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时间(ms为单位,0会立即返回,-1将不确定或称永久阻塞)。
#include
#include
#include
#include
#include
#include
#include
#include
#define IPADDRESS "127.0.0.1"
#define PORT 9877
#define MAXSIZE 1024
#define LISTENQ 5
#define FDSIZE 1000
#define EPOLLEVENTS 100
#define SA struct sockaddr
void add_event(int epollfd,int fd,int state);
void handle_events(int epollfd,struct epoll_event* events,int num,int listenfd,char* buf);
void handle_accpet(int epollfd,int listenfd);
void do_read(int epollfd,int fd,char* buf);
void do_write(int epollfd,int fd,char* buf);
void delete_event(int epollfd,int fd,int state);
void modify_event(int epollfd,int fd,int state);
int main(){
int listenfd,epollfd;
struct sockaddr_in serv;
struct epoll_event events[EPOLLEVENTS];
char buf[MAXSIZE];
int ret;
listenfd=socket(AF_INET,SOCK_STREAM,0);
bzero(&serv,sizeof(serv));
serv.sin_family=AF_INET;
serv.sin_port=htons(PORT);
serv.sin_addr.s_addr=htonl(INADDR_ANY);
bind(listenfd,(SA*)&serv,sizeof(serv));
listen(listenfd,LISTENQ);
bzero(buf,MAXSIZE);
epollfd=epoll_create(FDSIZE);//create a fd. FDSIZE represent the maximum number of fd.
add_event(epollfd,listenfd,EPOLLIN);//add fd(listenfd) to epollfd
while(true){
ret=epoll_wait(epollfd,events,EPOLLEVENTS,-1);//-1 representnever block.
hand_events(epollfd,events,ret,listenfd,buf);
}
close(epollfd);
}
/*
struct epoll_event{
_uint32_t events;//Epoll events
epoll_data_t data;//User data variable
};
typedef union epoll_data{
void* ptr;
int fd;
uint32_t u32;
uint64_t u64;
}epoll_data_t;
*/
void add_event(int epollfd,int fd,int state){
struct epoll_event ev;
ev.events=state;
ev.data.fd=fd;
epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev);//epoll事件注册函数,表明监听何种类型的事件
}
void hand_events(int epollfd,struct epoll_event *events,int num,int listenfd,char* buf){
int fd;
for(int i=0;i
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define IPADDRESS "127.0.0.1"
#define SERV_PORT 9877
#define MAXSIZE 1024
#define LISTENQ 5
#define FDSIZE 1000
#define EPOLLEVENTS 100
#define SA struct sockaddr
void add_event(int epollfd,int fd,int state);
void handle_events(int epollfd,struct epoll_event* events,int num,int listenfd,char* buf);
void handle_accpet(int epollfd,int listenfd);
void do_read(int epollfd,int fd,char* buf);
void do_write(int epollfd,int fd,char* buf);
void delete_event(int epollfd,int fd,int state);
void modify_event(int epollfd,int fd,int state);
int count=0;
int main(int argc,char* argv[]){
int sockfd,epollfd;
struct sockaddr_in serv;
struct epoll_event events[EPOLLEVENTS];
char buf[MAXSIZE];
int ret;
sockfd=socket(AF_INET,SOCK_STREAM,0);
bzero(&serv,sizeof(serv));
serv.sin_family=AF_INET;
serv.sin_port=htons(SERV_PORT);
inet_pton(AF_INET,IPADDRESS,&serv.sin_addr);
connect(sockfd,(SA*)&serv,sizeof(serv));
epollfd=epoll_create(FDSIZE);
add_event(epollfd,STDIN_FILENO,EPOLLIN);
for(;;){
ret=epoll_wait(epollfd,events,EPOLLEVENTS,-1);
handle_events(epollfd,events,ret,sockfd,buf);
}
close(sockfd);
}
void add_event(int epollfd,int fd,int state){
struct epoll_event ev;
ev.events=state;
ev.data.fd=fd;
epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&ev);
}
void hand_events(int epollfd,struct epoll_event *events,int num,int sockfd,char* buf){
int fd;
for(int i=0;i