1.epoll反应堆(了解)
epoll反应堆建立思路:
#include <stdio.h> #include <sys/socket.h> #include <sys/epoll.h> #include <arpa/inet.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <time.h> #define MAX_EVENTS 1024 #define BUFLEN 4096 #define SERV_PORT 8080 void recvdata(int fd,int events ,void *arg); void senddata(int fd,int events ,void *arg); /*Describes information about the ready file descriptor */ struct myevents_s{ int fd; //The file descriptor to listen int events; //The corresponding listening event void *arg;//Generic type pointer void (*call_back)(int fd,int events,void *arg); //callback function int status;//1->listen 0-> stop to listen char buf[BUFLEN]; int len; long last_active;//Record the time value of each addition of red-black tree "g_efd" }; int g_efd;//A global variable that holds the file descriptor returned by "epoll_create" struct myevent_s g_events[MAX_EVENTS+1];//+1--->listen fd /*Initialize the structure "myevent_s"*/ //eventset(&g_events[MAX_EVENTS],lfd,acceptconn,&g_events[MAX_EVENTS]); //void acceptconn(int lfd ,int events,void *arg) void eventset(struct myevent_s *ev,int fd,void (*call_back)(int,int,void *),void *arg) { ev->fd = fd; ev->call_back = call_back; ev->events = 0; ev->arg = arg; ev->status = 0; memset(ev->buf,0,sizeof(ev->buf)); ev->len = 0; ev->last_active = time(NULL); return; } /*Adds a file descriptor to the red-black tree on which epoll listens */ //eventadd(efd,EPOLLIN,&g_events[MAX_EVENTS]); void eventadd(int efd,int events,struct myevent_s *ev) { struct epoll_event epv ={0,{0}}; int op; epv.data.ptr =ev; epv.events = ev-> events = events; if(ev->status == 0){ op = EPOLL_CTL_ADD; ev->status = 1; } if(epoll_ctl(efd,op,e->fd,&epv)<0) printf("event add failed[fd = %d],events[%d]\n",ev->fd,events); else printf("event add OK [fd = %d],op= %d,events[%0X]\n",ev->fd,op,events); return; } // eventdel(g_efd,ev); void eventdel(int efd,struct myevent_s *ev) { struct epoll_event epv ={0,{0}}; if(ev->status != 1) return ; //epv.data.ptr=NULL; epv.data.ptr = NULL; ev->status = 0; epoll_ctl(efd,EPOLL_CTL_DEL,ev->fd.&epv); return ; } void acceptconn(int lfd ,int events,void *arg) { struct sockaddr_in cin; //client address socklen_t len = sizeof(cin); int cfd,i; if((cfd==accept(lfd,(struct sockaddr *)&cin,&len))==-1) { if(errno != EAGAIN && errno != EINTR) { /*not going to error handle it for now*/ printf("%s:accept,%s\n",__func__,strerror(errno)); return ; } do{ for(i = 0;i < MAX_EVENTS;i++)// if(g_events[i].status == 0)//Find a free element from the global array g events break; if(i == MAX_EVENTS){ printf("%s:max connect limit[%d]\n",__func__,MAX_EVENTS); break; } int flag = 0; if((flag = fcntl(cfd,F_SET,O_NONBLOCK))<0){ //cdf -->nonblocking printf("%s:fcntl nonblocking failed ,%s\n",__func__,strerror(errno)); break; } eventset(&g_events[i],cfd,recvdata,&g_events[i]); eventadd(g_efd,EPOLLIN,&g_events[i]); }while(0); printf("new connect [%s:%d][time :%ld],pos[%d]\n", inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),g_events[i].last_active,i); return ; } } /*create "socket", initlize "lfd" */ void initlistensocket(int efd,short port) { struct sockaddr_in sin; int lfd = socket(AF_INET,SOCK_STREAM,0); fcntl(lfd,F_SETFL,O_NONBLOCK);//Set the socket to non-blocking memset(&sin,0,sizeof(sin));//bzero(&sin,sizeof(sin)) sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); bind(lfd,(struct sockaddr *)&sin,sizeof(sin)); listen(lfd,20); /*void eventset(struct myevent_s *ev,int fd,void(*call_back)(int,int,void *),void *arg);*/ eventset(&g_events[MAX_EVENTS],lfd,acceptconn,&g_events[MAX_EVENTS]); /*void eventadd(int efd,int eventsmstruct myevent_s *ev) */ eventadd(efd,EPOLLIN,&g_events[MAX_EVENTS]); return ; } //eventset(&g_events[i],cfd,recvdata,&g_events[i]); void recvdata(int fd,int events,void *arg) { struct myevent_s *ev = (struct myevent_s *)arg; int len; len = recv(fd,ev->buf,sizeof(ev->buf),0); //=read(),only use in network programming,setting flags == 0; eventdel(g_efd,ev); if(len > 0){ ev->len = len; ev->buf[len]='\0'; printf("C[%d]:%s\n",fd,ev->buf); eventset(ev,fd,senddata,ev); eventadd(g_efd,EPOLLOUT,ev); }else if(len == 0){ close(ev->fd); printf("[fd=%d] pos[%ld],closed\n",fd,ev-g_events); }else{ close(ev->fd); printf("recv[fd=%d] error[%d]:%s\n",fd,errno,strerror(errno)); } return; } void senddata(int fd,int events,void *arg) { struct myevent_s *ev=(struct myevent_s *)arg; int len; len = send(fd,ev->buf,ev->len,0); eventdel(g_efd,ev); if(len > 0){ printf("send[fd = %d],[%d]%s\n",fd,len,ev->buf); eventset(ev,fd,recvdata,ev); eventadd(g_efd,EPOLLIN,ev); }else{ close(ev->fd); printf("send[fd=%d] error %s\n",fd,strerror(errno)); } return; } int main(int argc,char *argv[]) { unsigned short port = SERV_PORT; //Use the user-specified port. If no port is specified, use the default port if(argc == 2){ port = atoi(argv[1]); } g_efd = epoll_create(MAX_EVENTS+1);//create the red black tree, return "g_efd" if(g_efd <= 0) printf("create efd in %s err %s\n",_func_ ,strerror(errno)); initlistensocket(g_efd,port); //Initialize the listening socket struct epoll_event events[MAX_EVENTS+1];//Store an array of file descriptors that satisfy the ready events printf("server running : port[%d]\n",port); int checkpos = 0,i; while(1){ /*1.Timeout verification. Test 100 links each time without testing listenfd. If the client has not communicated with the server within 60 seconds, close the client link*/ long now = time(NULL);//present time for(i = 0;i<100;i++,checkpos++){//Check 100 at a time and use checkpos to control the check objects if(checkpos == MAX_EVENTS) checkpos = 0; if(g_events[checkpos].status != 1)//Not on the red-black tree "g_efd" continue; long duration = now - g_events[checkpos].last_active;//Time when the client is inactive if(duration >= 60){ close(g_events[checkpos].fd);//Close the link with the client printf("[fd=%d] timeout\n",g_events[checkpos].fd); eventdel(g_efd,&g_events[checkpos]);//Remove the client from the red black tree "g_efd" } } /*2.Listen to the red-black tree "g_efd" and add the described file descriptor to the events array. If no event is satisfied for 1 second, return 0*/ int nfd =epoll_wait(g_efd,events,MAX_EVENTS+1,1000);//timeout = 1000 if(nfd < 0){ printf("epoll_wait error,exit\n"); break; } for(i=0;i<nfd;i++){ /* Accepts void *ptr members of the union data using a custom struct pointer of type myevent_s */ struct myevent_s *ev = (struct myevent_s *)events[i].data.ptr; if((events[i].events & EPOLLIN)&&(ev -> events & EPOLLIN)){ //Read ready event ev->call_back(ev->fd,events[i].events,ev->arg); } if((events[i].events&EPOLLOUT)&&(ev->events & EPOLLOUT)){ //write ready event ev->call_back(ev->fd,events[i].events,ev->arg); } } } return 0; }