#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;
}
[转]一个关于epoll的例子
最新推荐文章于 2019-01-06 23:35:22 发布