#pragma once #include <errno.h> #include <sys/epoll.h> #include <sys/types.h> #include <sys/socket.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include "log.h"
#ifndef EPOLL_SIZE #define EPOLL_SIZE 4096 #define EPOLL_CONTEXT_SIZE (4096+256) #endif
typedef void * EPollerContext; class Epoller { public: Epoller(){} virtual ~Epoller(){} bool create() { memset(_contexts,0,sizeof(_contexts)); _handle=epoll_create(EPOLL_SIZE); if(_handle==-1) { glog.log(__FUNCTION__,"Epoll create error,errno is %d",errno); return false; } else return true; } void handle_events() { for(int i=0;i<_lastntfd;i++) { on_event(_events[i].data.fd,_events[i].events); } } int get_online_users() { int result=0; for(int i=0;i<EPOLL_CONTEXT_SIZE;i++) { if(_contexts[i]!=0) result++; } return result; } public: bool add(int fd,unsigned int events) { epoll_event polevt; polevt.events=events; polevt.data.fd=fd; return ctl(EPOLL_CTL_ADD,fd,polevt)==0; } bool del(int fd,unsigned int events) { epoll_event polevt; polevt.events=events; polevt.data.fd=fd; return ctl(EPOLL_CTL_DEL,fd,polevt)==0; } bool modify(int fd,unsigned int events) { epoll_event polevt; polevt.events=events; polevt.data.fd=fd; return ctl(EPOLL_CTL_MOD,fd,polevt)==0; } int poll(int timeout=5000) { _lastntfd=epoll_wait(_handle,_events,EPOLL_SIZE,timeout); return _lastntfd; } protected: int ctl(int op, int fd, struct epoll_event &event) { int ret=epoll_ctl(_handle,op,fd,&event); if(ret!=0) { glog.log(__FUNCTION__,"epoll_ctl fail,op is %d,fd is %d,errno is %d",op,fd,errno); } return ret; } protected: static bool setnonblocking(int sock) { int opts; opts=fcntl(sock,F_GETFL); if(opts<0) opts=O_NONBLOCK; else opts = opts|O_NONBLOCK; if(fcntl(sock,F_SETFL,opts)<0) { glog.log(__FUNCTION__,"setnoblock error"); return false; } else return true; }
static bool setreuseport(int sock) { int on=1; int ret=setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(int)); return ret!=-1; }
protected: virtual void on_event(int fd,int events){} private: int _handle; epoll_event _events[EPOLL_SIZE]; int _lastntfd; protected: EPollerContext _contexts[EPOLL_CONTEXT_SIZE]; EPollerContext get_context(int value) { return _contexts[value]; } bool set_context(int value,EPollerContext context) { _contexts[value]=context; } };
class ExampleServer : public Epoller { public: bool init(); void fini(); void check_timeout(); protected: void on_event(int fd,int events); private: void add_newsock(int sockvalue); void remove_sock(int sockvalue); private: int _listen_handler; };
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include "server.h" #include "clientmanager.h"
bool ExampleServer::init() { this->create(); _listen_handler=socket(AF_INET,SOCK_STREAM,0); setnonblocking(_listen_handler); setreuseport(_listen_handler); sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr=htonl(INADDR_ANY); serveraddr.sin_port=htons(ITEMLIST_SERVER_PORT); bind(_listen_handler,(sockaddr *)&serveraddr, sizeof(serveraddr)); listen(_listen_handler,ITEMCOMMENT_SERVER_LISTEN_BACKLOG); this->add(_listen_handler,EPOLLIN|EPOLLOUT); this->set_context(_listen_handler,0); }
void ExampleServer::fini() { close(_listen_handler); }
void ExampleServer::add_newsock(int sockvalue) { if(sockvalue>EPOLL_CONTEXT_SIZE) { glog.log(__FUNCTION__,"newsock is %d,> %d",sockvalue,EPOLL_CONTEXT_SIZE); close(sockvalue); return; }
ClientSession *newsession=gClientManager.alloc_client_session(sockvalue); if(newsession==NULL) { close(sockvalue); return; } if(add(sockvalue,EPOLLIN|EPOLLOUT)) { this->set_context(sockvalue,newsession); } else { gClientManager.release_client(newsession); close(sockvalue); } }
void ExampleServer::remove_sock(int sockvalue) { this->del(sockvalue,0); close(sockvalue); ClientSession *client=(ClientSession *)this->get_context(sockvalue); if(client) { gClientManager.release_client(client); } this->set_context(sockvalue,0); }
void ExampleServer::on_event(int fd,int events) { if(fd==_listen_handler) { sockaddr_in sa; memset(&sa,0,sizeof(sa)); socklen_t salen=sizeof(sa); int newsock=accept(_listen_handler,(sockaddr *)&sa,&salen); if(newsock>0) { add_newsock(newsock); } } else { ClientSession *client=(ClientSession *)this->get_context(fd); if(client!=NULL) { int newevents=client->handle_events(fd,events); if(newevents==0) { remove_sock(fd); } else this->modify(fd,newevents); } } }
void ExampleServer::check_timeout() { unsigned int curtime=time(NULL); for(int i=0;i<EPOLL_SIZE+256;i++) { ClientSession *client=(ClientSession *)this->get_context(i); if(client!=NULL) { if(curtime-client->get_last_io_time()>ITEMINDEX_SERVER_MAX_TIMEOUT) { remove_sock(i); } } } }
(iwgh) |