[libevent]Reactor反应器设计模式

前端之家收集整理的这篇文章主要介绍了[libevent]Reactor反应器设计模式前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

对象行为类的设计模式,对同步事件分拣和派发。别名Dispatcher@H_502_5@(分发器)@H_502_5@@H_502_5@

Reactor模式是处理并发I/O比较常见的一种模式,用于同步I/O,@H_502_5@中心思想是将所有要处理的I/O事件注册到一个中心I/O多路复用器上,同时主线程阻塞在多路复用器上;一旦有I/O事件到来或是准备就绪(区别在于多路复用器是边沿触发还是水平触发),多路复用器返回并将相应I/O事件分发到对应的处理器中。@H_502_5@

Reactor的事件处理机制@H_502_5@@H_502_5@

普通函数调用的机制:程序调用函数->函数执行,程序等待->函数将结果和控制权返回给程序->程序继续处理。而所谓事件驱动,简单地说就是你点什么按钮(@H_502_5@即产生什么事件@H_502_5@),@H_502_5@电脑执行什么操作@H_502_5@(@H_502_5@调用什么函数@H_502_5@)@H_502_5@。@H_502_5@事件驱动模型,如下图:@H_502_5@

@H_502_5@

Reactor@H_502_5@释义@H_502_5@“反应堆”,是一种事件驱动机制。和普通函数调用的不同之处在于:应用程序不是主动的调用某个@H_502_5@API@H_502_5@完成处理,而是恰恰相反,@H_502_5@Reactor@H_502_5@逆置了事件处理流程,应用程序需要提供相应的接口并注册到@H_502_5@Reactor@H_502_5@上,如果相应的时间发生,@H_502_5@Reactor@H_502_5@将主动调用应用程序注册的接口,这些接口又称为@H_502_5@“回调函数”。使用@H_502_5@Libevent@H_502_5@也是@H_502_5@向Libevent@H_502_5@框架注册相应的事件和回调函数;当这些时间发声时,@H_502_5@Libevent@H_502_5@调用这些回调函数处理相应的事件(@H_502_5@I/O@H_502_5@读写、定时和信号)。@H_502_5@

Reactor模式与Observer模式在某些方面极为相似:当一个主体发生改变时,所有依属体都得到通知。不过,观察者模式与单个事件源关联,而反应器模式则与多个事件源关联。@H_502_5@@H_502_5@

Reactor模式的优点@H_502_5@@H_502_5@

Reactor模式是编写高性能网络服务器的必备技术之一@H_502_5@,它具有如下的优点:@H_502_5@

  1. 响应快,不必为单个同步时间所阻塞,虽然@H_502_5@Reactor@H_502_5@本身依然是同步的;@H_502_5@
  2. 编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程@H_502_5@/@H_502_5@进程的切换开销;@H_502_5@
  3. 可扩展性,可以方便的通过增加@H_502_5@Reactor@H_502_5@实例个数来充分利用@H_502_5@cpu@H_502_5@资源;@H_502_5@
  4. 可复用性,@H_502_5@reactor@H_502_5@框架本身与具体事件处理逻辑无关,具有很高的复用性;@H_502_5@

Reactor模式框架@H_502_5@@H_502_5@

使用Reactor模型,必备的几个组件:事件源、Reactor框架、多路复用机制和事件处理程序。@H_502_5@Reactor@H_502_5@模型的整体框架,如下图:@H_502_5@


@H_502_5@@H_502_5@

Reactor@H_502_5@模型UML,如下图:@H_502_5@
@H_502_5@@H_502_5@

@H_502_5@

  • Handle——@H_502_5@@H_502_5@事件源@H_502_5@

Handle代表操作系统管理的资源,包括:网络链接,打开的文件,计时器,同步对象等等。@H_502_5@Linux@H_502_5@上是文件描述符,@H_502_5@Windows@H_502_5@上就是@H_502_5@Socket@H_502_5@或者@H_502_5@Handle@H_502_5@了,这里统一称为@H_502_5@“句柄集”;程序在指定的句柄上注册关心的事件,比如I/O@H_502_5@事件,信号,定时器。@H_502_5@@H_502_5@

  • eventdemultiplexer——事件多路分发机制@H_502_5@

由操作系统提供的I/O多路复用机制,比如select和epoll。程序首先将其关心的句柄(事件源)及其事件注册到eventdemultiplexer上;@H_502_5@

当有事件到达时,eventdemultiplexer会发出通知“在已经注册的句柄集中,一个或多个句柄的事件已经就绪”;程序收到通知后,就可以在非阻塞的情况下对事件进行处理了。@H_502_5@对应到libevent中,依然是select、poll、epoll等,但是libevent使用结构体eventop进行了封装,以统一的接口来支持这些I/O多路复用机制,达到了对外隐藏底层系统机制的目的。@H_502_5@

事件分离器,由操作系统提供,在linux上一般是select,poll,epoll等系统调用,在一个Handle集合上等待事件的发生。接受client连接,建立对应client的事件处理器(EventHandler),并向事件分发器(Reactor)注册此事件处理器.@H_502_5@

  • Reactor——反应器@H_502_5@

Reactor@H_502_5@,是事件管理的接口,内部使用@H_502_5@eventdemultiplexer@H_502_5@注册、注销事件;并运行事件循环,当有事件进入@H_502_5@“就绪”状态时,调用注册事件的回调函数处理事件。@H_502_5@

提供接口:注册删除和派发EventHandler@H_502_5@。@H_502_5@EventDemultiplexer@H_502_5@等待事件的发生,当检测到新的事件,就把事件交给@H_502_5@InitiationDispatcher@H_502_5@,它去回调@H_502_5@EventHandler@H_502_5@。@H_502_5@@H_502_5@

对应到libevent中,就是event_base结构体。@H_502_5@@H_502_5@一个典型的Reactor声明方式@H_502_5@

class Reactor 
{ 
public: 
int register_handler(Event_Handler *pHandler,int event); 
int remove_handler(Event_Handler *pHandler,int event); 
void handle_events(timeval *ptv); 
// ... 
};
  • EventHandler——事件处理程序@H_502_5@

事件处理程序提供了一组接口,每个接口对应了一种类型的事件,供Reactor@H_502_5@在相应的事件发生时调用,执行相应的事件处理。通常它会绑定一个有效的句柄。@H_502_5@@H_502_5@

事件处理器,负责处理特定事件的处理函数。一般在基本的Handler@H_502_5@基础上还会有更进一步的层次划分,用来抽象诸如@H_502_5@decode@H_502_5@,@H_502_5@process@H_502_5@和@H_502_5@encoder@H_502_5@这些过程。比如对@H_502_5@WebServer@H_502_5@而言,@H_502_5@decode@H_502_5@通常是@H_502_5@HTTP@H_502_5@请求的解析,@H_502_5@process@H_502_5@的过程会进一步涉及到@H_502_5@Listner@H_502_5@和@H_502_5@Servlet@H_502_5@调用。为了简化设计,@H_502_5@EventHandler@H_502_5@通常被设计成状态机,按@H_502_5@GoF@H_502_5@的@H_502_5@statepattern@H_502_5@来实现。@H_502_5@@H_502_5@对应到libevent中,就是event结构体。@H_502_5@下面是两种典型的EventHandler类声明方式,二者互有优缺点。@H_502_5@

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; 
// ... 
};
  • ConcreteEventHandler

继承上面的类,实现钩子方法。应用把ConcreteEventHandler@H_502_5@注册到@H_502_5@Reactor@H_502_5@,等待被处理的事件。当事件发生,这些方法被回调。@H_502_5@@H_502_5@@H_502_5@

应用场景举例@H_502_5@

场景:长途客车在路途上,有人上车有人下车,但是乘客总是希望能够在客车上得到休息。@H_502_5@

传统做法:每隔一段时间(或每一个站),司机或售票员对每一个乘客询问是否下车。@H_502_5@

Reactor做法:汽车是乘客访问的主体(@H_502_5@Reactor@H_502_5@),乘客上车后,到售票员(@H_502_5@acceptor@H_502_5@)处登记,之后乘客便可以休息睡觉去了,当到达乘客所要到达的目的地后,售票员将其唤醒即可。@H_502_5@@H_502_5@

猜你在找的React相关文章