[转]一个关于epoll的例子

#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstdio>
#include <errno.h>
#include <iostream>
#include <cstring>
using namespace std;

#define MAX_EVENTS 500
struct myevent_s
{
	int fd;
	void (*call_back)(int fd, int events, void *arg);
	int events;
	void *arg;
	int status; //1:in epoll wait list. 0:not in
	char buff[128]; //recv data buffer
	int len;
	int s_offset;
	long last_active; //last active time
};

//set event
void EventSet(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;
	bzero(ev->buff, sizeof(ev->buff));
	ev->s_offset = 0;
	ev->len = 0;
	ev->last_active = time(NULL);
}

//add/mod event to epoll
void EventAdd(int epollFd, int events, myevent_s *ev)
{
	struct epoll_event epv;
	int op;
	epv.data.ptr = ev;
	epv.events = ev->events = events;
	if (ev->status == 1)
	{
		op = EPOLL_CTL_MOD;
	}
	else
	{
		op = EPOLL_CTL_ADD;
		ev->status = 1;
	}
	if (epoll_ctl(epollFd, op, ev->fd, &epv) < 0)
	{
		perror("");
	}
}

void EventDel(int epollFd, myevent_s *ev)
{
	struct epoll_event epv;
	if (ev->status != 1)
	{
		return ;
	}
	epv.data.ptr = ev;
	ev->status = 0;
	epoll_ctl(epollFd, EPOLL_CTL_DEL, ev->fd, &epv);
}


//
int g_epollFd;
myevent_s g_events[MAX_EVENTS + 1]; //g_events[MAX_EVENTS] is used by listen fd.
void RecvData(int fd, int events, void *arg);
void SendData(int fd, int events, void *arg);

//accept new connections from clients
void AcceptConn(int fd, int events, void *arg)
{
	struct sockaddr_in sin;
	socklen_t len = sizeof(sin);
	int nfd, i;
	if ((nfd = accept(fd, (struct sockaddr *)&sin, &len)) == -1)
	{
		if (errno != EAGAIN && errno != EINTR)
		{
			//??
		}
		perror("");
		return ;
	}

	do
	{
		for (i=0; i<MAX_EVENTS; i++)
		{
			if (g_events[i].status == 0)
			{
				break;
			}
		}
		if (i == MAX_EVENTS)
		{
			close(nfd);
			cout << "max connection limit" << endl;
			break;
		}
        //set nonblocking
        int iret = 0;
        if ((iret = fcntl(nfd, F_SETFL, O_NONBLOCK)) < 0)
        {
            perror("");
            break;
        }

        //add a read event for receive data
        EventSet(&g_events[i], nfd, RecvData, &g_events[i]);
        EventAdd(g_epollFd, EPOLLIN, &g_events[i]);
	} while (0);
	cout << "new connection" << endl;

}

void RecvData(int fd, int events, void *arg)
{
	struct myevent_s *ev = (struct myevent_s *)arg;
	int len;
	len = recv(fd, ev->buff + ev->len, sizeof(ev->buff)-1-ev->len, 0);
	EventDel(g_epollFd, ev);
	if (len > 0)
	{
		ev->len += len;
		ev->buff[len] = '\0';
		cout << fd << ends << ev->buff << endl;
		EventSet(ev, fd, SendData, ev);
		EventAdd(g_epollFd, EPOLLOUT, ev);
	}
	else if (len == 0)
	{
		close(ev->fd);
		cout << "closed gracefully" << endl;
	}
	else
	{
		close(ev->fd);
		perror("");
	}
}

//send data
void SendData(int fd, int events, void *arg)
{
	struct myevent_s *ev = (struct myevent_s *)arg;
	int len;
	len = send(fd, ev->buff + ev->s_offset, ev->len - ev->s_offset, 0);
	if (len > 0)
	{
		ev->s_offset += len;
		if (ev->s_offset == ev->len)
		{
			EventDel(g_epollFd, ev);
			EventSet(ev, fd, RecvData, ev);
			EventAdd(g_epollFd, EPOLLIN, ev);
		}
	}
	else
	{
		close(ev->fd);
		EventDel(g_epollFd, ev);
		perror("");
	}
}

void InitListenSocket(int epollFd, short port)
{
	int listenFd = socket(AF_INET, SOCK_STREAM, 0);
	fcntl(listenFd, F_SETFL, O_NONBLOCK); //set non-blocking
	cout << "server listen fd=" << listenFd << endl;
	EventSet(&g_events[MAX_EVENTS], listenFd, AcceptConn, &g_events[MAX_EVENTS]);
	//add listen socket
	EventAdd(epollFd, EPOLLIN, &g_events[MAX_EVENTS]);
	//bind & listen
	sockaddr_in sin;
	bzero(&sin, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr.s_addr = htonl(INADDR_ANY);
	bind(listenFd, (struct sockaddr *)&sin, sizeof(sin));
	listen(listenFd, 5);
}

int main(int argc, char **argv)
{
	unsigned short port = 12345; //default port
	g_epollFd = epoll_create(MAX_EVENTS);
	if (g_epollFd <= 0)
	{
		perror("");
		exit(0);
	}
	//create & bind listen socket, and add to epoll, set non-blocking
	InitListenSocket(g_epollFd, port);
	//event loop
	struct epoll_event events[MAX_EVENTS];
	cout << "server running..." << endl;
	int checkPos = 0;
	while (true)
	{
		//a simple timeout check here, every time 100, better to use a miniheap, and add
		//timer event
		long now = time(NULL);
		for (int i=0; i<100; i++, checkPos++) //dosen't check listen fd
		{
			if (checkPos ==MAX_EVENTS)
			{
				//recycle
				checkPos = 0;
			}
			if (g_events[checkPos].status != 1)
			{
				continue;
			}
			long duration = now = g_events[checkPos].last_active;
			if (duration >= 60) //60s timeout
			{
				close(g_events[checkPos].fd);
				cout << "timeout" << endl;
				EventDel(g_epollFd, &g_events[checkPos]);
			}
		}
		//wait for events to happen
		int fds = epoll_wait(g_epollFd, events, MAX_EVENTS, 100);
		if (fds < 0)
		{
			perror("");
			exit(0);
		}
		for (int i=0; i<fds; i++)
		{
			myevent_s *ev = (struct myevent_s *)events[i].data.ptr;
			//read event
			if ((events[i].events & EPOLLIN) && (ev->events && EPOLLIN))
			{
				ev->call_back(ev->fd, events[i].events, ev->arg);
			}
			//write event
			if ((events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT))
			{
				ev->call_back(ev->fd, events[i].events, ev->arg);
			}
		}
	}
	//free resource
	return 0;
}

















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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值