ibevent:
reactor反应堆模型:
关键部分:
1) 事件源
Linux上是文件描述符,Windows上就是Socket或者Handle了,这里统一称为“句柄集”;程序在指定的句柄上注册关心的事件,比如I/O事件。
2) event demultiplexer——事件多路收集和分发机制(其实就是epoll等,直接运用在reactor中)
由操作系统提供的I/O多路复用机制,比如select和epoll。
程序首先将其关心的句柄(事件源)及其事件注册到event demultiplexer上;
当有事件到达时,event demultiplexer会发出通知“在已经注册的句柄集中,一个或多个句柄的事件已经就绪”;
程序收到通知后,就可以在非阻塞的情况下对事件进行处理了。
对应到libevent中,依然是select、poll、epoll等,但是libevent使用结构体eventop进行了封装,以统一的接口来支持这些I/O多路复用机制,达到了对外隐藏底层系统机制的目的。
3) Reactor——反应器
Reactor,是事件管理的接口,内部使用event demultiplexer注册、注销事件;并运行事件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数处理事件。
对应到libevent中,就是event_base结构体。
一个典型的Reactor声明方式
class Reactor { public: int register_handler(Event_Handler *pHandler, int event); int remove_handler(Event_Handler *pHandler, int event); void handle_events(timeval *ptv); // ... };
4) Event Handler——事件处理程序,(注意,事件处理函数是一个整体,这个整体可以注册,跟事件绑定在一起,换句话说,这个事件处理函数类,声称对这个事件感兴趣(所谓的事件,就是读写事情等等)
事件处理程序提供了一组接口,每个接口对应了一种类型的事件,供Reactor在相应的事件发生时调用,执行相应的事件处理。通常它会绑定一个有效的句柄。
对应到libevent中,就是event结构体。
下面是两种典型的Event Handler类声明方式,二者互有优缺点。
class Event_Handler { public: virtual void handle_read() = 0; virtual void handle_write() = 0; virtual void handle_timeout() = 0; virtual void handle_close() = 0; virtual HANDLE get_handle() = 0; // ... }; class Event_Handler { public: // events maybe read/write/timeout/close .etc virtual void handle_events(int events) = 0; virtual HANDLE get_handle() = 0; // ... };
然后就在reactor中不停的循环wait_epoll,这利用demultiplexer中函数进行,同时reactor的hanle_events是(当事件源就绪的时候,回调之前注册过的时间处理函数)通过转接demultiplexer中的函数,由于,得到的就绪的fd,可以得使他就绪的事件,根据handle和事件处理函数之间的关系,通过map存储,这样就可以得到注册的事件处理函数,然后又根据事件类型(写还是读),调用事件处理类中的对应函数
每个事件处理类,对应一个handle,但是一个同样的handle可以跟多个事件处理类对应(不同时刻)。这个handle有aceept生成。
int ReactorImplementation::RegisterHandler(EventHandler * handler, event_t evt) //参数是事件处理类和事件,但是通过事件处理类中的GetHandle()函数得到事件处理类对应的handle事件源。然后进行handle和事件处理类之间的对应关系的 { // map
handle_t handle = handler->GetHandle();
std::map<handle_t, EventHandler *>::iterator it = m_handlers.find(handle);
if (it == m_handlers.end())
{
m_handlers[handle] = handler;
}
return m_demultiplexer->RequestEvent(handle, evt);
}
map<handle_t, EventHandler *> m_handlers;//可知道socket描述符和事件处理类有一对一的关系。。wait_epoll得到就绪的fd还有引发fd就绪的事件,就可以回调当初与事件绑定的事件处理类(回调)
每个fd都有相应事件,如果对应fd上面的事件就绪,就返回fd,又因为注册的时候,事件是跟事件处理类对应的,事件处理类声称对事件感兴趣。所以可以根据,fd找到对应的就绪事件,然后回调事件处理类。注册事件的函数的参数是fd类型和事件处理类类型。