文章目录
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;
}