#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using std::cin;
using std::cout;
using std::endl;
using std::string;
#define SERV_PORT 6666
#define BACKLOG 128
#define BUFLEN 1024
#define MAXUSER 1024
struct event_s {
int fd;
int events;
void *arg;
void (*call_back)(int fd, int events, void *arg);
int status;
char buf[BUFLEN];
int len;
long last_active;
};
void RecvData(int fd, int events, void *arg);
void SendData(int fd, int events, void *arg);
void SysError(const char * msg);
void InitListenSocket(int efd, unsigned short serv_port);
void EventSet(event_s *events, int fd, void (*fun)(int, int, void *), void *arg);
void EventAdd(int efd, int events, event_s *evt);
void EventDel(int efd, event_s *evt);
void AcceptConn(int lfd, int events, void *arg);
int g_efd;
struct event_s g_events[MAXUSER + 1];
int main(int argc, char *argv[]) {
unsigned short serv_port = SERV_PORT;
if(argc == 2) {
serv_port = atoi(argv[1]);
}
g_efd = epoll_create(MAXUSER);
InitListenSocket(g_efd, serv_port);
struct epoll_event wait_events[MAXUSER + 1];
bzero(&wait_events, sizeof(wait_events));
puts("server running.");
int checkpos = 0, i;
while(1) {
long now = time(nullptr);
for(int i = 0; i < 100; i++, checkpos++) {
if(checkpos == MAXUSER) checkpos = 0;
if(g_events[checkpos].status == 0) continue;
long duration = now - g_events[checkpos].last_active;
if(duration >= 60) {
#if DEBUG
printf("duration = %ld\n", duration);
#endif
close(g_events[checkpos].fd);
printf("[fd=%d] timeout\n", g_events[checkpos].fd);
EventDel(g_efd, &g_events[checkpos]);
}
}
int nfd = epoll_wait(g_efd, wait_events, MAXUSER + 1, 1000);
if(nfd < 0) {
SysError("epoll_wait error.");
}
#if DEBUG
printf("nfd = %d\n", nfd);
#endif
for(int i = 0; i < nfd; i++) {
struct event_s *ev = (event_s *)wait_events[i].data.ptr;
if((wait_events[i].events & EPOLLIN) && (ev->events & EPOLLIN)) {
#if DEBUG
puts("EPOLLIN");
#endif
ev->call_back(ev->fd, wait_events[i].events, ev->arg);
}
if((wait_events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT)) {
ev->call_back(ev->fd, wait_events[i].events, ev->arg);
}
}
}
return 0;
}
void SysError(const char * msg) {
perror(msg);
exit(1);
}
void InitListenSocket(int efd, unsigned short serv_port) {
for(int i = 0; i < MAXUSER + 1; i++) {
g_events[i].fd = 0;
}
int lfd = socket(AF_INET, SOCK_STREAM, 0);
if(lfd == -1) {
string errMsg = (string)__func__ + " failed.";
SysError(errMsg.c_str());
}
fcntl(lfd, F_SETFL, O_NONBLOCK);
int opt = 1;
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
EventSet(&g_events[MAXUSER], lfd, AcceptConn, (void *)&g_events[MAXUSER]);
EventAdd(g_efd, EPOLLIN, &g_events[MAXUSER]);
sockaddr_in serv_addr;
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(serv_port);
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(lfd, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
register const string errMsg = (string)__func__ + ": bind error.";
SysError(errMsg.c_str());
}
register int lis = listen(lfd, BACKLOG);
if(lis == -1) {
SysError("InitListenSocket listen failed.");
}
puts("Listen Success...");
}
void RecvData(int fd, int events, void *arg) {
struct event_s *ev = (struct event_s *)arg;
int len = recv(fd, ev->buf, sizeof(ev->buf), 0);
#if DEBUG
printf("%s: len=%d\n", __func__, len);
#endif
EventDel(g_efd, ev);
if(len > 0) {
ev->len = len;
ev->buf[len]='\0';
printf("C: [%d]%s\n", ev->len - 1, ev->buf);
EventSet(ev, fd, SendData, (void *)ev);
EventAdd(g_efd, EPOLLOUT, (event_s *)ev->arg);
} else if(len == 0) {
close(ev->fd);
printf("[fd=%d] has offline.", ev->fd);
} else {
SysError("RecvData error.");
}
return;
}
void SendData(int fd, int events, void *arg) {
struct event_s *ev = (struct event_s *)arg;
#if DEBUG
printf("SendData buf = %s\n", ev->buf);
#endif
int len = send(ev->fd, ev->buf, ev->len, 0);
if(len > 0) {
printf("send[fd=%d], [%d]%s\n", fd, len - 1, ev->buf);
EventDel(g_efd, ev);
EventSet(ev, fd, RecvData, (void *)ev);
EventAdd(g_efd, EPOLLIN, ev);
} else {
close(ev->fd);
EventDel(ev->fd, ev);
printf("send[fd=%d] error: %s\n", fd, strerror(errno));
}
return;
}
void EventSet(event_s *events, int fd, void (*fun)(int, int, void *), void *arg) {
events->fd = fd;
events->arg = arg;
events->events = 0;
events->status = 0;
events->call_back = fun;
events->last_active = time(NULL);
return ;
}
void EventAdd(int efd, int events, event_s *evt) {
epoll_event epv = {0, {0}};
epv.events = evt->events = events;
epv.data.ptr = (void *)evt;
int op = EPOLL_CTL_ADD;
if(evt->status == 1) {
op = EPOLL_CTL_MOD;
} else {
evt->status = 1;
}
if(epoll_ctl(g_efd, op, evt->fd, &epv) < 0) {
printf("event add [fd=%d] failed.\n", evt->fd);
} else {
printf("event add [fd=%d] OK.\n", evt->fd);
}
return ;
}
void EventDel(int efd, event_s *evt) {
epoll_event epv = {0, {0}};
if(evt->status != 1) return;
epv.data.ptr = evt;
evt->status = 0;
epoll_ctl(g_efd, EPOLL_CTL_DEL, evt->fd, &epv);
}
void AcceptConn(int lfd, int events, void *arg) {
#if DEBUG
puts("AcceptConn");
#endif
sockaddr_in client_addr;
memset(&client_addr, 0, sizeof(client_addr));
socklen_t len = sizeof(client_addr);
int cfd = accept(lfd, (sockaddr *)&client_addr, &len);
if(cfd < 0) {
SysError("AcceptConn accept error.");
}
int pos = 0;
for(pos = 0; pos < MAXUSER; pos++) {
if(g_events[pos].fd == 0) {
break;
}
}
if(pos == MAXUSER) {
puts("User Online is Max.");
close(cfd);
return;
}
#if DEBUG
printf("AcceptConn: cfd = %d\n", cfd);
#endif
fcntl(cfd, F_SETFL, O_NONBLOCK);
EventSet(&g_events[pos], cfd, RecvData, (void *)&g_events[pos]);
EventAdd(g_efd, EPOLLIN, &g_events[pos]);
char IP[50];
inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, IP, sizeof(IP));
printf("[IP=%s] with [port=%d] has online.\n", IP, ntohs(client_addr.sin_port));
return;
}