`

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

    博客分类:
  • ACE
阅读更多

在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_Streampeer对象用来进行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=0;
    if((rev = peer.recv(buffer,1000))>0)
    {
        buffer[rev]='\0';
        cout<<endl<<"rev:\t"<<buffer<<endl;
        return 0;
    }
    else    //Socket连接发生错误,返回-1,在Reactor中注销事件,触发handle_close函数
    {
        return -1;
    }
}

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(3000,"127.0.0.1");
    ACE_Time_Value timeout(5,0);
    if(connector.connect(client.Peer(),addr,&timeout) != 0)
    {
        cout<<endl<<"connecetd fail";
        return 0;
    }

    ACE_Reactor::instance()->register_handler(&client,ACE_Event_Handler::READ_MASK);

while(true)
{
ACE_Reactor::instance()->handle_events(); 
}

return 0; 
}
 

在这里可以看到,使用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)模式的深入分析

    ACE反应器(Reactor)模式是一种用于处理并发事件的架构设计模式,主要应用于网络服务器的开发,特别是处理大量并发连接的场景。它有效地解决了在单线程或多线程环境中,如何高效地处理多个I/O事件的问题。Reactor模式...

    Reactor反应器的实现方法详解

    创建自定义反应器实例后,可以使用`ACE_Reactor::instance()`方法替换默认的反应器实例,并指定是否在程序结束时删除这个实例。 3. **具体的Reactor实现** - **ACE_Select_Reactor**:这是在除Windows外的大多数...

    C++ Network Programming, Volume 2: Systematic Reuse with ACE and Frameworks

    - 第4章提供了ACE反应器不同实现的详细介绍,包括ACE_Select_Reactor、ACE_TP_Reactor和ACE_WFMO_Reactor类,每种实现都有其特定的使用场景和优势。 5. ACE服务配置器框架 - 第5章介绍了ACE服务配置器框架,展示...

    ace_reactor:王牌React堆服务器

    Ace Reactor提供了多种反应器实现,包括基于select、poll、epoll等不同操作系统原生API的版本,以适应不同的性能和规模需求。例如,Linux系统的epoll机制在高并发下表现出色,因为它支持水平触发和边缘触发两种模式...

    ACE开发指南(初级)

    ACE的核心特性包括反应器(Reactor)和预行动器(Proactor)模式,它们是事件驱动设计的关键部分。 2.2 **环境搭建** 在开始开发前,需要安装ACE库,并配置开发环境。这通常包括下载源码,编译安装,然后在项目中链接...

    ACE框架知识

    反应器操作 - **close()**: 关闭并释放由`ACE_Reactor`使用的资源。 - **register_handler(ACE_Event_Handler*, ACE_Reactor_Mask)**: 注册事件处理器到`ACE_Reactor`,并指定感兴趣的事件类型。 - **remove_...

    ACE学习文档大全.rar

    5. **ACE反应器(Reactor)模式**: Reactor模式是ACE的核心,它负责监听和分发网络事件。开发者需要理解Reactor的事件处理机制,如事件注册、调度策略、回调函数等。同时,Reactor的异步I/O模型也是学习的重点,它...

    ACE 程序员指南 源代码

    7. **分布式系统设计**:ACE_TSS(Thread Specific Storage)用于线程局部存储,ACE_Logger提供日志记录,ACE_WFMO_Reactor实现了Windows下的基于WaitFOrMultipleObjects的反应器。 8. **性能优化**:ACE_Dynamic_...

    ACE程序员指南

    3. **ACE组件**:包括ACE_TSS(线程特定存储)、ACE_Reactor(事件反应器)、ACE_Scheduler(调度器)、ACE_Proactor(异步操作处理器)等。每个组件都有其特定的功能,如Reactor用于事件驱动编程,Proactor则适用于...

    ACE简单例子 并附说明

    - **反应器模型**:ACE的反应器(`ACE::Reactor`)是处理I/O事件的核心组件。 - **设计模式的应用**:ACE广泛采用了设计模式,如单例模式、适配器模式、迭代器模式等。 ##### 2. 内存管理 - **缓存内存分配类ACE_...

    ACE.rar_ACE

    1. **ACE框架结构**:ACE主要由几个核心组件构成,如Reactor(事件反应器)、Thread Manager(线程管理器)、Tokenizer(分词器)等,它们共同构成了一个强大的网络通信框架。 2. **Reactor模式**:这是ACE的核心...

    开源利器ACE

    调用方可以将自己关心的事件及其处理函数在反应器中注册,当特定的事件发生时,由反应器在其线程环境中调用预先指定的函数。 ACE_Acceptor/Connector 封装客户端和服务器的连接过程,并使用了类厂模式,在连接建立...

    ACE开发指南(初级).

    ##### 3.1 Reactor(反应器)框架 Reactor模式是一种常见的事件驱动设计模式,它将事件处理与事件接收解耦,使得系统更加灵活和可扩展。 ###### 3.1.1 ACE_Event_Handler(事件处理器) 在ACE框架中,`ACE_Event_...

    ACE技术论文集(已翻译为中文)

    第 7 章 ACE 反应器(Reactor)的设计和使用:用于事件多路分离的面向对象框架 第 8 章 前摄器(Proactor):用于为异步事件多路分离和分派处理器的对象行为模式 第 9 章 接受器-连接器(Acceptor-Connector):...

    一个简单的ace C/S 供学习参考

    2. `ACE_Reactor`: 反应器模式是ACE中的核心设计模式,用于处理并发事件。`ACE_Reactor`负责调度事件处理,当有新的连接或数据到达时,它会调用相应`ACE_Handler`的回调函数。 3. `ACE_Acceptor`: ACE提供`ACE_...

    ACE经典教程 经典

    ACE是基于事件驱动和反应器模式的库,它提供了一系列接口和工具,用于简化网络编程、并发处理和系统资源管理。ACE支持多种操作系统,包括Windows、Linux、Unix等,确保代码的可移植性。 2. ACE核心概念: - 事件...

    ACE自适配通信环境中文技术文档.pdf

    Process Communication,进程间通信)、I/O、Active Object(活动对象设计模式)、Reactor(反应器模式)、Proactor(前摄器模式)、Acceptor(接受器模式)以及众多操作系统平台,例如UNIX、Win32、Linux、Mac OS、...

Global site tag (gtag.js) - Google Analytics