epoll是Linux下多路复用接口select/poll的增强版本。
- 它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符集合来传递结果而不用每次等待时间之前都必须重新准备要被监听的文件描述符集合
- 获取事件的时候,它无须遍历整个被监听的文件描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了
- 目前
epoll
是Linux大规模并发网络程序中的热门首选模型 - 除了提供
select/poll
那种IO事件的电平触发外,还提供了边沿触发,这使得用户空间程序有可能暂存IO状态,减少epoll_wait/epoll_pwait
的调用,提高应用程序效率
epoll
基础API
1 epoll_create
函数
函数原型
int epoll_create(int size);
- 功能
创建一个epoll
句柄,参数size
用来告诉内核监听的文件描述符的个数,跟内存大小有关。 - 参数
size
:监听数目
2 epoll_ctl
函数
函数原型
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
-
功能
控制某个epoll
监控的文件描述符上的事件:注册、修改、删除。
-
参数
epfd
:为epoll_create
的句柄
event
:告诉内核需要监听的事件
op
:表示动作,常用的三个宏
EPOLL_CTL_ADD
:注册新的fd到epfdEPOLL_CTL_MOD
:修改已经注册的fd的监听事件EPOLL_CTL_DEL
:从epfd删除一个fd
-
两个结构体
struct epoll_event{
_uint32_t events;
epoll_data_t data;
}
struct union epoll_data{
void* ptr;
int fd;
uint32_t u32;
uint64_t u64;
}epoll_data_t;
3 epoll_wait
函数
函数原型
int epoll_wait(int epfd,struct epoll_event *events,int maxevents, int timeout);
- 功能
等待所监控文件描述符上有事件的产生,类似于select()
调用 - 参数
events
:用来存内核得到事件的集合
maxevents
:告诉内核这个events
有多大,这个maxevents
的值不能大于创建epoll_create()
时的size
timeout
:超时时间
- 返回值
成功返回有多少满足条件的文件描述符。
超时时间到时返回0,出错返回-1.
例子
#include <stdio.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define IP "127.0.0.1"
#define PORT 8888
int main()
{
int sfd = socket(AF_INET,SOCK_STREAM,0);
int opt = 1;
setsockopt(sfd,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof (opt));
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
inet_pton(AF_INET,IP,&serv_addr.sin_addr.s_addr);
socklen_t serv_len = sizeof (serv_addr);
int ret = bind(sfd,(struct sockaddr*)&serv_addr,serv_len);
if(ret != 0){
printf("bind error:%s\n",strerror(ret));
exit(1);
}
listen(sfd,128);
while(1){
int epfd = epoll_create(10);
if(ret < 0){
perror("epoll_create error");
exit(2);
}
struct epoll_event inevent;
inevent.events = EPOLLIN;
inevent.data.fd = sfd;
epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&inevent);
while(1){
struct epoll_event outevent[10];
ret = epoll_wait(epfd,outevent,sizeof (outevent),-1);
for(int i = 0; i < ret;i++){
printf("-----------%d------------\n",i);
if(!(outevent[i].events & EPOLLIN))
continue;
int sockfd = outevent[i].data.fd;
if(outevent[i].data.fd == sfd){
struct sockaddr_in clie_addr;
socklen_t clie_len = sizeof (clie_addr);
sockfd = accept(sfd,(struct sockaddr*)&clie_addr,&clie_len);
char buf[BUFSIZ];
memset(buf,0,sizeof (buf));
printf("%s connected, port: %d\n",inet_ntop(AF_INET,&clie_addr.sin_addr.s_addr,buf,
sizeof (buf)),ntohs(clie_addr.sin_port));
struct epoll_event cevent;
cevent.events = EPOLLIN;
cevent.data.fd = sockfd;
epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&cevent);
}else{
char rwbuf[BUFSIZ];
memset(rwbuf,0,sizeof (rwbuf));
int len = read(sockfd,rwbuf,sizeof (rwbuf));
if(len == 0){
printf(" client disconnected\n");
close(sockfd);
epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,outevent);
}else if(len > 0){
for(int j = 0; j < len; j++){
rwbuf[j] = toupper(rwbuf[j]);
}
write(sockfd,rwbuf,len);
}
}
}
}
}
close(sfd);
return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)