了解一下
Epoll 是一种高效的管理socket的模型,相对于select和poll更加高效。
数据结构
- sys/epoll.h
typedef union epoll_data {
void ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
struct epoll_event {
__uint32_t events; / Epoll events /
epoll_data_t data; / User data variable /
};
(1) epoll_data 联合体用来保存触发事件的某个文件描述符相关的数据.
(2) epoll_event 结构体的events字段是表示感兴趣的事件和被触发的事件:
EPOLLIN :表示对应的文件描述符可以读;
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET:表示对应的文件描述符设定为edge模式
函数
*epoll_create, epoll_create1 函数
函数声明:int epoll_create(int size)
该函数生成一个epoll专用的文件描述符,其中的参数是指定生成描述符的最大范围。
- epoll_ctl函数
函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event event) 该函数用于控制某个文件描述符上的事件,可以注册事件,修改事件,删除事件。
参数:epfd:由 epoll_create 生成的epoll专用的文件描述符;
op:要进行的操作例如注册事件:
EPOLL_CTL_ADD 注册、
EPOLL_CTL_MOD 修改、
EPOLL_CTL_DEL 删除
- epoll_wait函数
函数声明: int epoll_wait(int epfd,struct epoll_event events,int maxevents,int timeout) 该函数用于轮询I/O事件的发生;
参数:
epfd: 由epoll_create 生成的epoll专用的文件描述符;
epoll_event: 用于回传代处理事件的数组;
maxevents: 每次能处理的事件数;
timeout: 等待I/O事件发生的超时值(ms);-1永不超时,直到有事件产生才触发,0立即返回。返回发生事件数。-1有错误。
Sample:
int main()
{
//声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件
struct epoll_event ev,events[20];
epfd=epoll_create(10000); //创建epoll句柄
listenfd = socket(AF_INET, SOCK_STREAM, 0);
//把socket设置为非阻塞方式
setnonblocking(listenfd);
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port=htons(SERV_PORT);
bind(listenfd,(struct sockaddr )&serveraddr, sizeof(serveraddr));
listen(listenfd, 255);
//设置与要处理的事件相关的文件描述符
ev.data.fd=listenfd;
//设置要处理的事件类型
ev.events=EPOLLIN;
//注册epoll事件
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
for ( ; ; )
{
//等待epoll事件的发生
nfds=epoll_wait(epfd,events,20,1000);
//处理所发生的所有事件
for(i=0;i<nfds;++i)
{
if(events .data.fd==listenfd)
{
connfd = accept(listenfd,(struct sockaddr )&clientaddr, &clilen);
if(connfd<0)
{
perror("connfd<0");
}
setnonblocking(connfd);
//设置用于读操作的文件描述符
ev.data.fd=connfd;
//设置用于注测的读操作事件
ev.events=EPOLLIN|EPOLLET;
//注册event
epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
}
else if(events .events&EPOLLIN)
{
read_socket(events .data.fd);
ev.data.fd=events .data.fd;
ev.events=EPOLLIN|EPOLLOUT|EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
}
else if(events .events&EPOLLOUT)
{
write_socket(events .data.fd);
ev.data.fd=events .data.fd;
ev.events=EPOLLIN|EPOLLET; //ET模式
epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
}
else
{
perror("other event");
}
}
}
}