1为什么要反应器模型
前面的文章有个共同的特点,那就是针对一对一的通信情况,甚至双方通信的先后都是定式的。对于要处理多个输入输出/网络连接,传统的应用都要创建新的并发单元(进程或线程),每个输入输出/网络连接一个并发单元。这可以很好的工作,但是带来的运行时开销也是很大的,在一些情况下,是无法接受的。同时,并发单元的管理控制使代码变得异常复杂,如果驾驽的不够火候,就会陷入灾难之中。这种复杂已使很多人望而却步。
反应器的基础是使用select()、poll()、WaitForMultipleObjects()等系统函数做事件的多路分离。当一个输入输出/网络连接口有事件发生时(可读/可写),反应器会调用相应的事件处理函数。
2反应器模型的实现
事件处理器(ACE_Reactor)通过事件循环(run_reactor_event_loop),对所有已注册(register_handler)的事件处理器(ACE_Event_Handler)进行检测,当其中有事件处理器的句柄(get_handle)有事件发生时(可读/可写),调用该事件处理器相应的处理函数。类图如下:
图表 2-1
序列图:
图表 2-2
2.1 事件处理器
ACE提供了事件处理器的基类:ACE_Event_handler。用户(程序开发者)通过继承该类,需要实现事件处理函数接口:
- get_handler:返回IO文件描述符,对于TCP网络,为socket
- handle_input:当IO口有数据可读入时,反应器自动调用该事件函数
- hanle_output:当IO口可写时,反应器自动调用该事件
- handle_close:当handle_input/handle_output返回值为-1(表示该IO 口已无效,对于TCP,则表示对方以关闭,网络断开了)时,调用该事件函数
事件处理函数返回值的含义:
返回值 | 说明 |
-1 | 反应器删除该事件登记,并调用 handle_close 函数 |
0 | 正常情况,反应器继续分发事件 |
>0 | 让反应器暂时不分发事件,继续回调该事件函数 |
2.2 反应器
用户通过使用反应器的register_handler,把事件处理器登记到反应器中。在事件循环处理的时候,会对已登记的事件处理器进行事件探测,当有事件发生时,调用其相应的事件处理器。
事件注册的一个原型为:
register_handler ( ACE_Event_Handler * event_handler, ACE_Reactor_Mask mask)
event_handler为要注册的事件处理器指针。mask为注册的事件类型,参考如下:
事件 处理函数 说明
事件 | 处理函数 | 说明 |
ACE_Event_Handler::READ_MASK | handle_input | 当 IO 口可读时调用 |
ACE_Event_Handler::WRITE_MASK | handle_output | 当 IO 可写时调用 |
ACE_Event_Handler::ACCEPT_MASK | handle_input | 对于服务端 socket ,当有客户端连接时调用 |
反应器的另一个应用是调度定时器,通过schedule_timer函数设定定时信息,当定时事件到达,调用事件处理器的handle_timeout函数。