加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

反应器组件 ACE_Reactor

发布时间:2020-12-15 05:26:29 所属栏目:百科 来源:网络整理
导读:6.1 反应器组件 ACE_Reactor 反应器的基本原理 是: 针对关心的某个事件写一个事件处理器(event_handler). 将该事件处理器登记到反应器中(同时指明关心的事件). 然后反应器会自动检测事件的发生. 并调用预先登记的事件处理器中的回调函数. 所以. 用户要做的工
6.1 反应器组件 ACE_Reactor

反应器的基本原理是:
针对关心的某个事件写一个事件处理器(event_handler). 将该事件处理器登记到反应器中(同时指明关心的事件).
然后反应器会自动检测事件的发生. 并调用预先登记的事件处理器中的回调函数.


所以.用户要做的工作就是:
创建事件处理器.
在反应器上登记该处理器. 告诉反应器它对某个事件有兴趣
.


6.2 事件处理器

在ACE中.反应器是ACE_Reactor类的单件对象(因为程序中通常只需要一个反应器).
反应器提供了登记/撤销 事件处理器的接口.register_handler() /remove_handler() .
这些接口要求 事件处理器必须是ACE_Event_Handler类型的. 所以我们的事件处理器类必须从该类继承.

在ACE_Event_Handler类中定义了一些类似"handle_***" 的回调方法. 我们必须在派生类中重写我们敢兴趣的.
在反应器需要检测某个I/O句柄上是否有事件时. 需要知道原始句柄. 这样就需要重写事件处理器类的get_handle()函数.
下边是ACE_Event_Handler 中声明的钩子函数:
handle_signal()当在反应器上登记的信号发生时. 反应器回调该函数. (不懂)
handle_input()当来自I/O设备的输入可用时. 反应器自动回调该方法.
handle_exception() 当在反应器上登记的异常事件发生时. (不懂)
handle_timeout()当在反应器上登记的定时器超时的时候. 回调该方法.
handle_output()当在IO设备上的输出可用时. 回调该方法.

6.2.1 登记事件处理器
使用 ACE_Reactor 类的register_handler()函数.这个函数有好几个重载形式.
该函数有个参数用来指出感兴趣的事件. 它可以是下边一些常量(定义在ACE_Event_handler类中):
READ_MASK句柄上有数据可读时回调 handle_input()
WRITE_MASK句柄上可写时回调 handle_output()
TIMER_MASK回调 handle_close() 不懂怎么用...
ACCEPT_MASK有来自客户端的新的连接请求时回调 handle_input()
CONNECT_MASK建立连接时回调 handle_input()
DONT_CALL它用在显式拆除事件处理器的remove_handler()函数中. 表示拆除前不调用 handler_close() 函数.


6.2.2 拆除事件处理器
当不在需要处理某个事件时. 需要把对应的事件处理器从反应器中拆除.
两种拆除事件处理器的办法:
一种是隐式的自动拆除.当事件处理器类中的 handle_*** 方法返回的int 小于0 时. 反应器会自动调用事件处理器
的Handle_close()方法. 并把事件处理器拆除.
另一种是显式拆除. 即调用 ACE_reactor::remove_handler(). 这也会调用事件处理器的handle_close(). 然后拆除.
不过. 如果你不需要调用handle_close(). 可以给remove_handler()传递参数 ACE_Event_Handler::DONT_CALL .
具体例子在后边会给出.


6.3 通过反应器进行事件处理
6.3.1 I/O事件多路分离

////////////////////////////////////
// 一个使用反应器的例子.
// (注意这里的例子不是71页那个. 因为那个例子小弟么看懂ing).
// 来自 <<ACE程序员教程>> 75页.
//用反应器来实现一个tcp的服务器. 连接的监听. 以及在接受的新连接的上的读取事件. 都在反应器中进行.
///////////////////////////////////

//服务器端
#include "ace/Reactor.h"
#include "ace/Event_Handler.h"
#include "ace/SOCK_Acceptor.h"

const int PORT_NO = 19999; //服务器监听的端口号.
typedef ACE_SOCK_Acceptor Acceptor;
class My_Accept_Handler;

// 一个事件处理器类.
//处理其中维护的TCP流对象 peer_ 上发生的输入事件.
class My_Input_Handler : publicACE_Event_Handler{
public:
// 重写基类中的handle_input() 函数.
inthandle_input(ACE_HANDLE) {//接口中这个参数的作用是??
peer_.recv_n(data,12);//书中是 peer().recv_n(data,12); 但不知peer()从何而来....
// 输出 data...
return 0;//该函数的返回值如果小于0. 则反应器会在调用完后撤销该事件处理器的登记.
}

// 下边的函数会被反应器使用. 来得到会发生事件的底层句柄.
ACE_HANDLE get_handle() const{
return peer_.get_handle(); //取得TCP流对象的原始句柄
}
private:
ACE_SOCK_Stream peer_;
char data[12];
};

// 另一个事件处理器类. 处理接受器收到的连接的事件
class My_Accept_Handler : publicACE_Event_Handler{
public :
My_Accept_Handler(ACE_Addr & addr) {
open(addr);
}
int open(ACE_Addr &addr) {
peer_acceptor.open(addr);// 接受器的 open() 函数 和构造函数中直接传递addr 都可以使接受器监听该地址.
return 0;
}
// 重写基类中的handle_input()
inthandle_input(ACE_HANDLE handle) {
My_Input_Handler *eh = new My_Input_Handler; // 刚才定义的那个类.
if (peer_acceptor.accept(//接受一个连接
eh->peer_,//一个要捆绑的ACE_SOCK_Stream对象. (peer_是私有的. 这里本来不能直接访问. 偷懒一下马马虎虎..)
0,//这个参数用来返回前来连接的客户的地址.
0,//超时时间
1) //这个参数不懂ing..
== -1)
ACE_DEBUG((LM_ERROR,"Error in connectionn"));
//然后给反应器中增加一个事件处理器. 来处理这个新连接上的输入事件.
ACE_Reactor::instance()->register_handler(eh,ACE_Event_Handler::READ_MASK);

return-1; //返回负数.表示希望反应器在处理一个连接请求后. 自动注销本处理器.
}
// 要重写基类中的get_handle() 函数. 来帮助反应器取得内部句柄
ACE_HANDLEget_handle() const {
return peer_acceptor.get_handle();
}
private:
acceptor peer_acceptor; //接受器
};

int main() {
ACE_INET_Addr addr(PORT_NO);
My_Accept_Handler * eh = new My_Accept_Handler(addr);

// 登记eh到反应器中
ACE_Reactor::instance() -> register_handler(eh,ACE_Event_Handler::ACCEPT_MASK);

while(1)
ACE_Reactor::instance() ->handle_events(); //处理事件 }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读