转载于:http://www.cnblogs.com/TianFang/archive/2006/12/18/595808.html

在Socket编程中,常见的事件就是"读就绪","写就绪",通过对这两个事件的捕获分发,可以实现Socket中的异步操作。

Socket编程中的事件处理器

在前面我们已经介绍过,在ACE反应器框架中,任何都必须派生自ACE_Event_Handler类,并通过重载其相应会调事件处理函数来实现相应的回调处理的。在Socket编程中,我们通常需要重载的函数有

  1. handle_input()
    当I/O句柄(比如UNIX中的文件描述符)上的输入可用时,反应器自动回调该方法。
  2. handle_output()
    当I/O设备的输出队列有可用空间时,反应器自动回调该方法。
  3. handle_close()
    当事件处理器中的事件从Reactor中移除的时候调用。

此外,为了使Reactor能通过I/O句柄找到对应的事件处理器,还必须重载其get_handle()方法以使得Reactor建立起I/O句柄和事件处理器的关联。

使用Reactor框架。

下面我们将以一个客户端的程序为例,介绍如何在Socket编程中使用Reactor框架。

一.建立一个客户端对象(事件处理器)。

客户端对象就是一个事件处理器,其声明如下:

 class Client:public ACE_Event_Handler
{
public:
ACE_HANDLE get_handle(void) const;
int handle_input (ACE_HANDLE fd);
int handle_close (ACE_HANDLE handle,
ACE_Reactor_Mask close_mask);
ACE_SOCK_Stream& Peer();
private:
ACE_SOCK_Stream peer;
};

在Client端中我只关心"读就绪"事件,故只重载了handle_input函数(大多数应用下只需要重载handle_input函数)。另外,在客户端还保存了一个ACE_SOCK_Stream的peer对象用来进行Socket通信,同时封装了一个Peer()函数返回它的引用。

二.重载相应回调处理函数

 ACE_SOCK_Stream& Client::Peer()
{
return peer;
} ACE_HANDLE Client::get_handle(void) const
{
return peer.get_handle();
} int Client::handle_input (ACE_HANDLE fd)
{
int rev=;
if((rev = peer.recv(buffer,))>)
{
buffer[rev]='\0';
cout<<endl<<"rev:\t"<<buffer<<endl;
return ;
}
else //Socket连接发生错误,返回-1,在Reactor中注销事件,触发handle_close函数
{
return -;
}
} int Client::handle_close (ACE_HANDLE handle,
ACE_Reactor_Mask close_mask)
{
cout<<endl<<"connecetd closed";
return ACE_Event_Handler::handle_close(handle,close_mask);
}

几个函数的功能都非常简单,这里就不多做介绍了。

三.在Reactor中注册事件

首先让我们来看看相应的main函数的代码:

 int main(int argc, char *argv[])
{
Client client;
ACE_SOCK_Connector connector;
ACE_INET_Addr addr(,"127.0.0.1");
ACE_Time_Value timeout(,);
if(connector.connect(client.Peer(),addr,&timeout) != )
{
cout<<endl<<"connecetd fail";
return ;
} ACE_Reactor::instance()->register_handler(&client,ACE_Event_Handler::READ_MASK); while(true)
{
ACE_Reactor::instance()->handle_events();
} return ;
}

在这里可以看到,使用Reactor框架后,依然首先通过ACE_SOCK_Connector的connect函数来建立连接。建立连接后,可以通过ACE_Reactor::instance()->register_handler函数来实现Reactor的注册,实现I/O事件和Client对象的handle_input方法相关联,它的第一个参数是事件处理器的地址,第二个参数是事件类型,由于这里只关心读就绪事件,故注册的事件类型是ACE_Event_Handler::READ_MASK。

四.启动Reactor事件循环

通过如上设置后,我们就可以通过ACE_Reactor::instance()->handle_events()启动Reactor循环了,这样,每当服务器端有数据发送给客户端时,当客户端的数据就绪时,就回触发Client对象的handle_input函数,将接收的数据打印出来。

通常的做法是,将Reactor事件循环作为一个单独的线程来处理,这样就不会阻塞main函数。

五.注销Reactor事件

Reactor事件的注销一般有两种方式,显式和隐式,下面将分别给予介绍。

  1. 隐式注销。
    当Reactor捕获事件后,会触发相应的"handle_"处理函数,当"handle_"处理函数返回值大于或等于0时,表示处理事件成功,当返回值小于0时,表示处理事件失败,这时Reactor会自动注销该句柄所注册的所有事件,并触发handle_close函数,以执行相应的资源清理工作。
    在本例中,当handle_input函数里的recv函数接收到0个数时,说明socket发生错误(大多为Socket连接中断),此时返回-1,则系统自动注销相应事件。
  2. 显示注销。
    调用Reactor对象的remove_handler方法移除,它有两个参数,第一个是所注册的事件反应器对象,第二个是所要注销的事件。

在这个示例程序里,连接方只有一个Socket连接,Reactor的优势并没有体现出来,但在一些网络管理系统里,连接方需要对多个需要管理的设备(服务器端)进行连接,在这种情况下使用Reactor模式,只需要多开一个Reactor事件循环线程就能实现事件多路分发复用,并且不会阻塞,通过面向对象的回调方式管理,使用起来非常方便。

Reactor框架的另外一个常用的地方就是服务器端,一般是一个服务器端对应多个客户端,这样用Reactor模式能大幅提高并发能力,这方面的编程方法将在下一章给与介绍。

ACE反应器(Reactor)模式(2)的更多相关文章

  1. ACE反应器(Reactor)模式(1)

    转载于:http://www.cnblogs.com/TianFang/archive/2006/12/13/591332.html 1.ACE反应器框架简介 反应器(Reactor):用于事件多路分 ...

  2. ACE反应器(Reactor)模式(4)

    转载于:http://www.cnblogs.com/TianFang/archive/2006/12/18/596012.html 定时器的实现 通过Reactor机制,还可以很容易的实现定时器的功 ...

  3. ACE反应器(Reactor)模式(3)

    转载于:http://www.cnblogs.com/TianFang/archive/2006/12/18/595938.html 在服务器端使用Reactor框架 使用Reactor框架的服务器端 ...

  4. 反应器(Reactor)模式

    Java NIO非堵塞技术实际是采取反应器模式,或者说是观察者(observer)模式为我们监察I/O端口,如果有内容进来,会自动通知我们,这样,我们就不必开启多个线程死等,从外界看,实现了流畅的I/ ...

  5. ACE - Reactor模式源码剖析及具体实现(大量源码慎入)

    原文出自http://www.cnblogs.com/binchen-china,禁止转载. 在之前的文章中提到过Reactor模式和Preactor模式,现在利用ACE的Reactor来实现一个基于 ...

  6. 什么是Reactor模式,或者叫反应器模式

    Reactor这个词译成汉语还真没有什么合适的,很多地方叫反应器模式,但更多好像就直接叫reactor模式了,其实我觉着叫应答者模式更好理解一些.通过了解,这个模式更像一个侍卫,一直在等待你的召唤,或 ...

  7. Reactor模式,或者叫反应器模式

    Reactor这个词译成汉语还真没有什么合适的,很多地方叫反应器模式,但更多好像就直接叫reactor模式了,其实我觉着叫应答者模式更好理解一些.通过了解,这个模式更像一个侍卫,一直在等待你的召唤,或 ...

  8. Reactor模式(反应器模式)

    Reactor这个词译成汉语还真没有什么合适的,很多地方叫反应器模式,但更多好像就直接叫reactor模式了,其实我觉着叫应答者模式更好理解一些.通过了解,这个模式更像一个侍卫,一直在等待你的召唤,或 ...

  9. Reactor模式,或者叫反应器模式 - 为什么用多路io复用提供吞吐量

    Reactor这个词译成汉语还真没有什么合适的,很多地方叫反应器模式,但更多好像就直接叫reactor模式了,其实我觉着叫应答者模式更好理解一些.通过了解,这个模式更像一个侍卫,一直在等待你的召唤,或 ...

随机推荐

  1. JVM之G1收集器

    Garbage-First,面向服务端的垃圾收集器. 并行与并发:充分利用多核环境减少停顿时间, 分代收集:不需要配合其它收集器 空间整合:整体上看属于标记整理算法,局部(region之间)数据复制算 ...

  2. Solidity中的基本类型转换

    Solidity中的基本类型转换(十四)|入门系列 2017/4/29 posted in Solidity入门系列 点击查看原文,获得优化的排版. 隐式转换 如果一个运算符能支持不同类型.编译器会隐 ...

  3. ServiceStack.Ormlit 使用Insert的时候自增列不会被赋值

    Insert签名是这样的,将第2个参数设置为true就会返回刚插入的自增列ID了,然后可以手工赋值到对象上面去 public static long Insert<T>(this IDbC ...

  4. RDL/RDLC批量单据打印 [转]

    RDL/RDLC批量单据打印 使用RDL或RDLC进行单据打印时,单张单据打印比较直观简单,无需说明.下面我们来谈一下批量单据打印的实现方法.以下以RDL的ReportBuilder设计环境为例进行讲 ...

  5. HADOOP docker(一):安装hadoop实验集群(略操蛋)

    一.环境准备 1.1.机器规划 主机名    别名    IP     角色 9321a27a2b91 hadoop1 172.17.0.10 NN1 ZK RM 7c3a3c9cd595 hadoo ...

  6. css重修之书(一):如何用css制作比1px更细的边框

    如何用css制作比1px更细的边框 在项目的开发过程中,我们常常会使用到border:1px solid xxx,来对元素添加边框: 可是1px的border看起来还是粗了一些粗,不美观,那么有什么方 ...

  7. 软件工程 作业part3 读后感

    匆匆看完构建之法,觉得这种不认真看完书就去写随笔去评价这本书是对作者的不尊重,所以觉得应该提问题和写感悟. 我的一点拙见,提的问题在现在这个信息发达的时候感觉只要有时间都可以自己解决. 感觉软件工程这 ...

  8. lintcode-163-不同的二叉查找树

    163-不同的二叉查找树 给出 n,问由 1...n 为节点组成的不同的二叉查找树有多少种? 样例 给出n = 3,有5种不同形态的二叉查找树: 标签 卡特兰数 动态规划 思路 参考博客http:// ...

  9. iOS- <项目笔记>iOS6 & iOS7屏幕图片适配

    1.为非视网膜\视网膜屏幕分别准备2份图片,比如: 1> 非视网膜 abc.png 2> 视网膜 abc@2x.png 程序检测视网膜屏到会自动替换@2x 2.程序启动图片 * 程序启动过 ...

  10. 关于JS里面写JAVA代码的问题

    最近做项目需要在JS脚本里面调用一个JAVA的函数得到数据,在网上查了很久,发现JS脚本里面不能写JAVA函数.只能把JS脚本里面的代码写进JSP文件里面的<script>标签内,然后写J ...