linux网络编程(六)epoll反应堆

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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值