Linux--epoll反应堆
epoll反应堆的概述
epoll反应堆的核心思想:将文件描述符、事件、回调函数用自定义结构体封装在一起,当某个文件描述符的事件被触发,调用其回调函数即可
示例代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>//socket
#include <netinet/in.h> //struct sockaddr_in
#include <strings.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <sys/epoll.h>int create_tcp_socket(unsigned short port);
void sys_err(const char *err);typedef void (*CALLBACK)(void *arg);
typedef struct {
int epfd; int fd;//文件描述符
int event; //存放事件
CALLBACK callback;
void *arg;
}MY_EVENT;void event_add(int epfd,int fd,int event,CALLBACK callback,MY_EVENT *my_ev_p){
my_ev_p->epfd = epfd;
my_ev_p->fd = fd;
my_ev_p->event = event;
my_ev_p->callback = callback;
struct epoll_event ev;
ev.events = event;
ev.data.ptr = my_ev_p;
epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev);
}void read_data(void *arg){
MY_EVENT *my_ev_p = (MY_EVENT *)arg;
unsigned char buf[1500] = "";
int n = recv(my_ev_p->fd,buf,sizeof(buf),0);
if (n <= 0)
{
struct epoll_event ev;
ev.events = my_ev_p->event;
ev.data.ptr = NULL;
epoll_ctl(my_ev_p->epfd,EPOLL_CTL_DEL,my_ev_p->fd,&ev);
close(my_ev_p->fd);
if(my_ev_p != NULL){
free(my_ev_p);
my_ev_p = NULL;
}
}else if (n > 0)
{
printf("%s\n",buf);
int res = send(my_ev_p->fd,buf,n,0);
if(res > 0){
printf("send success\n");
}
}
}void initAccept(void *arg){
MY_EVENT *my_ev_p = (MY_EVENT *)arg;
struct sockaddr_in cil_addr;
socklen_t cli_len = sizeof(cil_addr);
int cfd = accept(my_ev_p->fd,(struct sockaddr *)&cil_addr,&cli_len);
printf("connect %s : %hu\n",
inet_ntoa(cil_addr.sin_addr),ntohs(cil_addr.sin_port));
MY_EVENT *cfd_p = (MY_EVENT *)calloc(1,sizeof(MY_EVENT));
event_add(my_ev_p->epfd,cfd,EPOLLIN,read_data,cfd_p);
}int main(int argc,char *argv[]) {
int lfd = create_tcp_socket(9999);
int epfd = epoll_create(1);//创建epoll的树
MY_EVENT *lfd_p = (MY_EVENT *)calloc(1,sizeof(MY_EVENT)); event_add(epfd,lfd,EPOLLIN,initAccept,lfd_p);
struct epoll_event evs[1024];
while(1){
int n = epoll_wait(epfd,evs,1024,-1);
if(n <= 0){
sys_err("epoll_wait");
}else{
int i = 0;
for ( i = 0; i < n; i++)
{
MY_EVENT *p = evs[i].data.ptr;
p->callback(p);
}
}
}
close(epfd);
close(lfd);
return 0;
}int create_tcp_socket(unsigned short port){
int lfd = socket(AF_INET,SOCK_STREAM,0);
if(lfd < 0)
sys_err("socket error");
int opt = 1;
setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
struct sockaddr_in my_addr;
bzero(&my_addr,sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(port);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(lfd,(struct sockaddr *)&my_addr,sizeof(my_addr));
if(ret < 0)
sys_err("bind error");
listen(lfd,128);
return lfd;
}void sys_err(const char *err){
perror(err);
_exit(-1);
}