libevent C++面向对象的封装
作者:方振涛
对event_base操作的封装如下:
class TEventContext { public: static void InitLib() { WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); WSAStartup(wVersionRequested, &wsaData); } public: TEventContext(event_base* evbase=NULL):m_evBase(evbase){} ~TEventContext(){ if (m_evBase) { event_base_free(m_evBase); } } bool Init() { if(m_evBase) return false; m_evBase=event_base_new(); return m_evBase!=NULL; } bool ReInit() { return event_reinit(m_evBase)==0; } bool Dispatch()//进入事件处理循环 { return event_base_dispatch(m_evBase)==0; } const char*GetMethod() { return event_base_get_method(m_evBase); } int GetFeatures(){return event_base_get_features(m_evBase);} enum { FLoopOnce=EVLOOP_ONCE, FLoopNonBlock=EVLOOP_NONBLOCK, }; //进入事件循环 bool Loop(int flags) { return event_base_loop(m_evBase,flags)==0; } //退出循环 bool ExitLoop( const struct timeval *timev) { return event_base_loopexit(m_evBase,timev)==0; } bool BreakLoop() { return event_base_loopbreak(m_evBase)==0; } bool GotExit() { return event_base_got_exit(m_evBase)!=0; } bool GotBreak() { return event_base_got_break(m_evBase)!=0; } event_base* GetEvBase() { return m_evBase; } private: event_base* m_evBase; };封装对event的操作:
class TEvent { public: TEvent() { memset(&m_event,0,sizeof(m_event)); } template<class EventHandler> bool Assign(TEventContext* ctx,EventHandler* handler) { return event_assign(&m_event,ctx->GetEvBase(),handler->GetFd(),handler->GetType(),EventHandler::HandlerFunc,handler)==0; } bool Add(const struct timeval *tmv) { return event_add(&m_event,tmv)==0; } bool Remove() { return event_del(&m_event)==0; } void Active(int res, short ncalls) { event_active(&m_event,res,ncalls); } bool CheckPending(short events, struct timeval *tv) { return event_pending(&m_event,events,tv)!=0; } bool IsInitialized() { return event_initialized(&m_event)!=0; } evutil_socket_t GetFd() { return event_get_fd(&m_event); } short GetEvent() { return event_get_events(&m_event); } private: TEvent(TEvent&){} TEvent& operator=(TEvent&){} struct event m_event;//仅保存数据 };下面来说说关于如何处理到来的事件:
一般很容易会想到事件到来后通过虚函数来实现对事件的处理,但对于服务器来说尽量做到高效率,使用虚函数会造成不必要的性能损失。
受到WTL库使用模板来替代虚函数,来完成对事件的处理。
事件的处理实现如下:
template<class Handler> class TEventHandler { public: enum EventFlag { FTimeOut=EV_TIMEOUT, FRead=EV_READ, FWrite=EV_WRITE, FSignal=EV_SIGNAL, FPersist=EV_PERSIST, FEt=EV_ET, }; public: TEventHandler(evutil_socket_t fd,short type):m_fd(fd),m_type(type){} static void HandlerFunc(evutil_socket_t fd, short eventType, void *arg) { TEventHandler* handler=(TEventHandler*)arg; handler->m_fd=fd; handler->m_type=eventType; handler->OnEventHandle(); } inline void OnEventHandle()//不能使用OnHandle,防止子类未重写导致死循环 { Handler* chandler= static_cast<Handler*>(this); chandler->OnHandle(); } evutil_socket_t GetFd(){return m_fd;} short GetType(){return m_type;} protected: evutil_socket_t m_fd; short m_type; };
在OnEventHandle函数中通过转换来实现调用相应子类实现的处理函数
template<class Handler> class TTimerHandler:public TEventHandler<Handler> { public: TTimerHandler():TEventHandler(-1,0){} }; template<class Handler> class TSingalHandler:public TEventHandler<Handler> { public: TSingalHandler(evutil_socket_t fd):TEventHandler(fd,EV_SIGNAL|EV_PERSIST){} };
测试代码如下:
struct timeval lasttime; int event_is_persistent; class MyHandler:public TTimerHandler<MyHandler> { public: TEvent* m_event; MyHandler(TEvent *ev):m_event(ev) {} void OnHandle() { struct timeval newtime, difference; double elapsed; evutil_gettimeofday(&newtime, NULL); evutil_timersub(&newtime, &lasttime, &difference); elapsed = difference.tv_sec + (difference.tv_usec / 1.0e6); printf("timeout_cb called at %d: %.3f seconds elapsed.\n", (int)newtime.tv_sec, elapsed); lasttime = newtime; if (! event_is_persistent) { struct timeval tv; evutil_timerclear(&tv); tv.tv_sec = 2; m_event->Add(&tv); } } }; int _tmain(int argc, char* argv[]) { if (argc == 2 && !strcmp(argv[1], "-p")) { event_is_persistent = 1; } else { event_is_persistent = 0; } TEventContext::InitLib(); TEventContext base; base.Init(); TEvent ev; MyHandler handler(&ev); ev.Assign(&base,&handler); struct timeval tv; evutil_timerclear(&tv); tv.tv_sec = 2; ev.Add(&tv); evutil_gettimeofday(&lasttime, NULL); base.Dispatch(); return 0; }
此文档属本人原创,欢迎转载。