- 前言
- 一、epoll
- 二、常用API:
- 三、使用步骤
- 1.服务器端(LT模式)
- 2.客户端
- 总结
前言
epoll原理以及使用。
提示:以下是本篇文章正文内容,下面案例可供参考
一、epollepoll 是 Linux 特有的 I/O 复用函数。它在实现和使用上与 select、poll 有很大差异。首先,epoll 使用一组函数来完成任务,而不是单个函数。其次,epoll 把用户关心的文件描述符上的事件放在内核里的一个事件表中。从而无需像 select 和 poll 那样每次调用都要重复传入文件描述符或事件集。但 epoll 需要使用一个额外的文件描述符,来唯一标识内核中的这个事件表。
二、常用API:◼ epoll_create()用于创建内核事件表
◼ epoll_ctl()用于操作内核事件表
◼ epoll_wait()用于在一段超时时间内等待一组文件描述符上的事件
代码如下(示例):
#include2.客户端#include #include #include #include #include #include #include #include #include #include #define MAX 10 void epoll_add(int epfd,int fd) { struct epoll_event ev; ev.events=EPOLLIN;//设置读事件 ev.data.fd=fd; if(epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev)==-1)//注册读事件 { perror("epoll_ctl_add errn"); } } void epoll_del(int epfd,int fd) { if(epoll_ctl(epfd,EPOLL_CTL_DEL,fd,NULL)==-1) { perror("epoll_ctl_del error"); } } int main() { int sockfd=socket(AF_INET,SOCK_STREAM,0); assert(sockfd!=-1); struct sockaddr_in saddr,caddr; memset(&saddr,0,sizeof(saddr)); saddr.sin_family=AF_INET; saddr.sin_port=htons(6000); saddr.sin_addr.s_addr=inet_addr("127.0.0.1"); int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr)); assert(res!=-1); res=listen(sockfd,5); assert(res!=-1); int epfd=epoll_create(MAX);//创建事件列表,实现方法是红黑树,因此max只要大于零即可 assert(epfd!=-1); epoll_add(epfd,sockfd); struct epoll_event evs[MAX]={0};//此处定义数组大小为10不意味着之可以取10个就绪事件,可循环取就绪事件数量 while(1) //此处定义的数组是为了存放就绪事件的描述符 { int n=epoll_wait(epfd,evs,MAX,5000);//根据epoll返回值看有几个事件就绪 if(-1==n) { perror("epoll_wait errn"); } else if(0==n) { printf("time outn"); } else { for(int i=0;i if(evs[i].events&EPOLLIN)//判断是什么事件,此程序只关注读事件,所以只判断读事件, { //若判断其他事件则继续与,例如写事件:if(evs[i]&EPOLLOUT),以此类推。 if(evs[i].data.fd==sockfd) { struct sockaddr_in caddr; int len=sizeof(caddr); int c=accept(sockfd,(struct sockaddr*)&caddr,&len); if(c<0) { continue; } else { printf("accept c=%dn",c); epoll_add(epfd,c); } } else { char buff[128]={0}; int num=recv(evs[i].data.fd,buff,127,0); if(num<=0) { epoll_del(epfd,evs[i].data.fd); close(evs[i].data.fd); printf("client closen"); continue; } else { printf("buff(%d)=%sn",evs[i].data.fd,buff); send(evs[i].data.fd,"ok",2,0); } } } } } }
代码如下(示例):
#include总结#include #include #include #include #include #include #include #include int main() { int sockfd=socket(AF_INET,SOCK_STREAM,0); assert(sockfd!=-1); struct sockaddr_in saddr; memset(&saddr,0,sizeof(saddr)); saddr.sin_family=AF_INET; saddr.sin_port=htons(6000); saddr.sin_addr.s_addr=inet_addr("127.0.0.1"); int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr)); assert(res!=-1); char buff[128]={0}; printf("input: n"); while(1) { fgets(buff,128,stdin); if(strncmp(buff,"end",3)==0) { break; } send(sockfd,buff,strlen(buff),0); memset(&buff,0,sizeof(buff)); recv(sockfd,buff,127,0); printf("buff=%sn",buff); } close(sockfd); exit(0); }
epoll与select、poll的区别:
epoll在每个描述符上都注册有回调函数,当描述符上有事件就绪时可以直接取得该描述符的值,因此时间为O(1)



