ACE反应器模式:ACE_Reactor

本文介绍了ACE_Reactor模式在服务器socket编程中的应用。利用ACE库实现客户端连接的处理与通信,通过ClientAcceptor被动接收客户端请求,并为每个连接创建ClientService进行管理。文章提供了具体的代码示例。

    在服务器socket编程中,用来处理客户端的请求,最直接的做法是,为每一个socket连接创建一个线程,采用阻塞模式的方法来处理,然这种阻塞模式随着并发量增大,效果也会越来越差。一种比较好的方法就是select模型的思想。比如可把来自客户端的连接保存在一个cook中,采用轮询的方式检测某个连接是否可读或者可写。ACE反应器模式与这种思想类似。

    ACE_Reactor的使用很简单,在服务端可以注册两个事件,一个用来处理客户端的连接,这种是被动接受客户端的请求,这里称作ClientAcceptor,当接受到客户端请求时,注册一个事件用来专门负责和客户端通信,这里称作ClientService。这样在有N个连接的服务器就会出现一个ClientAcceptor对象和N个ClientService对象,当某一个客户端连接断开则删除cook中的记录,并析构掉一个ClientService对象。

以下是服务器一个实例:

头文件需要包括:

#include<ace/OS.h>
#include<ace/Reactor.h>
#include<ace/SOCK_Connector.h>
#include<ace/SOCK_Acceptor.h>
#include<ace/Auto_Ptr.h>ClientAcceptor:专门负责处理来自客户端的连接
class ClientAcceptor : public ACE_Event_Handler
{
public:
    virtual ~ClientAcceptor (){this->handle_close (ACE_INVALID_HANDLE, 0);}

    int open (const ACE_INET_Addr &listen_addr)
    {
        if (this->acceptor_.open (listen_addr, 1) == -1)
        {
            ACE_OS::printf("open port fail");
            return -1;
        }
        //注册接受连接回调事件
        returnthis->reactor ()->register_handler(this, ACE_Event_Handler::ACCEPT_MASK);
    }

    virtual ACE_HANDLE get_handle (void) const
    { returnthis->acceptor_.get_handle (); }

    virtualint handle_input (ACE_HANDLE fd )
    {
        ClientService *client = new ClientService();
        auto_ptr<ClientService> p (client);

        if (this->acceptor_.accept (client->peer ()) == -1)
        {
            ACE_OS::printf("accept client fail");
            return -1;
        }
        p.release ();
        client->reactor (this->reactor ());
        if (client->open () == -1)
            client->handle_close (ACE_INVALID_HANDLE, 0);
        return 0;
    }
    
    virtualint handle_close (ACE_HANDLE handle,
        ACE_Reactor_Mask close_mask)
    {
        if (this->acceptor_.get_handle () != ACE_INVALID_HANDLE)
        {
            ACE_Reactor_Mask m = ACE_Event_Handler::ACCEPT_MASK |
                ACE_Event_Handler::DONT_CALL;
            this->reactor ()->remove_handler (this, m);
            this->acceptor_.close ();
        }
        return 0;
    }

protected:
    ACE_SOCK_Acceptor acceptor_;
};

ClientService:负责和客户端通信

class ClientService : public ACE_Event_Handler
{
public:
    ACE_SOCK_Stream &peer (void) { returnthis->sock_; }

    int open (void)
    {
        //注册读就绪回调函数
        returnthis->reactor ()->register_handler(this, ACE_Event_Handler::READ_MASK);
    }

    virtual ACE_HANDLE get_handle (void) const { returnthis->sock_.get_handle (); }

    virtualint handle_input (ACE_HANDLE fd )
    {
        //一个简单的EchoServer,将客户端的信息返回
        int rev = peer().recv(buf,100);
        if(rev<=0)
            return -1;

        peer().send(buf,rev);
        return 0;
    }

    // 释放相应资源
virtualint handle_close (ACE_HANDLE, ACE_Reactor_Mask mask)
    {
        if (mask == ACE_Event_Handler::WRITE_MASK)
            return 0;
        mask = ACE_Event_Handler::ALL_EVENTS_MASK |
            ACE_Event_Handler::DONT_CALL;
        this->reactor ()->remove_handler (this, mask);
        this->sock_.close ();
        deletethis;    //socket出错时,将自动删除该客户端,释放相应资源
        return 0;
    }

protected:
    char buf[100];
    ACE_SOCK_Stream sock_;
};

main函数就更简单了:

int main(int argc, char *argv[]) 
{
    ACE_INET_Addr addr(3000,"192.168.1.142");
    ClientAcceptor server;
    server.reactor(ACE_Reactor::instance());
    server.open(addr);

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

    return 0; 
}实际上ACE反应器的功能还很强大,实现了多事件分离机制,将不同的事件类型交给不同的事件处理器,通过框架内部一张表来维护。
下载前可以先看下教程 https://pan.quark.cn/s/a426667488ae 标题“仿淘宝jquery图片左右切换带数字”揭示了这是一个关于运用jQuery技术完成的图片轮播机制,其特色在于具备淘宝在线平台普遍存在的图片切换表现,并且在整个切换环节中会展示当前图片的序列号。 此类功能一般应用于电子商务平台的产品呈现环节,使用户可以便捷地查看多张商品的照片。 说明中的“NULL”表示未提供进一步的信息,但我们可以借助标题来揣摩若干核心的技术要点。 在构建此类功能时,开发者通常会借助以下技术手段:1. **jQuery库**:jQuery是一个应用广泛的JavaScript框架,它简化了HTML文档的遍历、事件管理、动画效果以及Ajax通信。 在此项目中,jQuery将负责处理用户的点击动作(实现左右切换),并且制造流畅的过渡效果。 2. **图片轮播扩展工具**:开发者或许会采用现成的jQuery扩展,例如Slick、Bootstrap Carousel或个性化的轮播函数,以达成图片切换的功能。 这些扩展能够辅助迅速构建功能完善的轮播模块。 3. **即时数字呈现**:展示当前图片的序列号,这需要通过JavaScript或jQuery来追踪并调整。 每当图片切换时,相应的数字也会同步更新。 4. **CSS美化**:为了达成淘宝图片切换的视觉效果,可能需要设计特定的CSS样式,涵盖图片的排列方式、过渡效果、点状指示器等。 CSS3的动画和过渡特性(如`transition`和`animation`)在此过程中扮演关键角色。 5. **事件监测**:运用jQuery的`.on()`方法来监测用户的操作,比如点击左右控制按钮或自动按时间间隔切换。 根据用户的交互,触发相应的函数来执行...
垃圾实例分割数据集 一、基础信息 • 数据集名称:垃圾实例分割数据集 • 图片数量: 训练集:7,000张图片 验证集:426张图片 测试集:644张图片 • 训练集:7,000张图片 • 验证集:426张图片 • 测试集:644张图片 • 分类类别: 垃圾(Sampah) • 垃圾(Sampah) • 标注格式:YOLO格式,包含实例分割的多边形点坐标,适用于实例分割任务。 • 数据格式:图片文件 二、适用场景 • 智能垃圾检测系统开发:数据集支持实例分割任务,帮助构建能够自动识别和分割图像中垃圾区域的AI模型,适用于智能清洁机器人、自动垃圾桶等应用。 • 环境监控与管理:集成到监控系统中,用于实时检测公共区域的垃圾堆积,辅助环境清洁和治理决策。 • 计算机视觉研究:支持实例分割算法的研究和优化,特别是在垃圾识别领域,促进AI在环保方面的创新。 • 教育与实践:可用于高校或培训机构的AI课程,作为实例分割技术的实践数据集,帮助学生理解计算机视觉应用。 三、数据集优势 • 精确的实例分割标注:每个垃圾实例都使用详细的多边形点进行标注,确保分割边界准确,提升模型训练效果。 • 数据多样性:包含多种垃圾物品实例,覆盖不同场景,增强模型的泛化能力和鲁棒性。 • 格式兼容性强:YOLO标注格式易于与主流深度学习框架集成,如YOLO系列、PyTorch等,方便研究人员和开发者使用。 • 实际应用价值:直接针对现实世界的垃圾管理需求,为自动化环保解决方案提供可靠数据支持,具有重要的社会意义。
<think>我们正在处理关于ACE框架中事件处理器注销的问题。根据引用内容,注销事件处理器有两种方式:隐式自动拆除和显式拆除。用户特别关注如何取消READ_MASK事件的处理,即注销对读事件的处理。引用[1]提到:-隐式拆除:当事件处理器类中的handle_***方法返回小于0时,反应器会自动调用handle_close()方法并拆除事件处理器。-显式拆除:调用ACE_reactor::remove_handler(),并可以选择是否调用handle_close()方法。引用[2]说明了事件处理器的基本使用步骤,包括注册和回调。引用[3]给出了一个代码示例,其中在handle_input方法中通过返回-1来触发隐式拆除(注意该示例中在accept后返回-1,这样会导致当前事件处理器被拆除?但实际上该示例中是在接收新连接后注册了新的处理器,并返回-1,那么它实际上是在每次接收一个连接后就会拆除自己?这显然不是我们想要的,因为通常接受器会持续工作。所以这里可能是个错误或者特殊设计?)用户的问题:如何注销ACE_Event_Handler中的READ_MASK事件?分析:我们想要注销的是某个事件处理器上的READ_MASK事件(即不再监听读事件),但保留其他事件(如果有)或者完全拆除该事件处理器。根据ACE文档,有两种方式:1.显式调用remove_handler()来移除特定的事件类型(如READ_MASK)或者移除整个事件处理器。2.在handle_*方法中返回一个负值(比如-1)来触发整个事件处理器的拆除(包括所有事件类型)。注意:如果我们只想移除READ_MASK,而保留其他事件(比如WRITE_MASK),那么就需要使用显式拆除并指定事件类型。具体方法:显式拆除:intremove_handler(ACE_HANDLEhandle,ACE_Reactor_Maskmask);其中,mask就是要移除的事件集,比如READ_MASK。代码示例:reactor()->remove_handler(handler->get_handle(),ACE_Event_Handler::READ_MASK);这样,反应器将不再监听该句柄上的读事件,但其他事件(如果注册了)还会继续监听。如果我们想完全移除该事件处理器,可以调用:reactor()->remove_handler(handler->get_handle(),ACE_Event_Handler::ALL_EVENTS_MASK);或者reactor()->remove_handler(handler);//这个版本不需要句柄,但需要事件处理器对象另外,在remove_handler时,默认会调用事件处理器的handle_close方法(传入mask参数为0)。如果不想调用handle_close,可以传递标志位ACE_Event_Handler::DONT_CALL。示例代码(参考引用[3]的格式):假设我们有一个事件处理器对象,它已经注册了读事件(READ_MASK)。现在我们要取消读事件监听:reactor->remove_handler(my_handler->get_handle(),ACE_Event_Handler::READ_MASK);如果我们在事件处理器内部调用,可以直接使用反应器实例:ACE_Reactor::instance()->remove_handler(get_handle(),ACE_Event_Handler::READ_MASK);注意:在移除特定事件后,如果该事件处理器还注册了其他事件,那么它仍然会处理那些事件。如果没有任何事件了,反应器将不再调用该事件处理器。另外,隐式方法:在handle_input方法中返回-1,将会导致整个事件处理器被拆除(即移除所有事件并调用handle_close)。但这样会移除所有事件,而不仅仅是读事件。因此,根据用户需求,如果只想注销READ_MASK,那么应该使用显式方法。下面给出一个代码示例片段:```cppclassMyEventHandler:publicACE_Event_Handler{public://...其他方法//假设我们想要在某个条件下取消读事件voidcancel_read_event(){//获取反应器实例ACE_Reactor*reactor=ACE_Reactor::instance();//移除当前句柄上的读事件reactor->remove_handler(this->get_handle(),ACE_Event_Handler::READ_MASK);}//句柄获取ACE_HANDLEget_handle()constoverride{//返回你管理的句柄,比如socket句柄returnyour_handle_;}//处理读事件inthandle_input(ACE_HANDLEh)override{//处理读事件...//如果我们在处理读事件的过程中决定不再监听读事件,可以在这里调用remove_handler//但注意:在handle_input中调用remove_handler(READ_MASK)是安全的吗?//根据ACE的规则,在事件处理函数中移除自己(部分事件)是允许的。//例如://if(some_condition){//ACE_Reactor::instance()->remove_handler(get_handle(),ACE_Event_Handler::READ_MASK);//}return0;//返回0表示继续监听,但我们已经移除了读事件,所以下次不会收到读事件了}//...其他部分};```重要:在事件处理函数(如handle_input)中调用remove_handler(READ_MASK)是安全的,因为反应器允许在回调中修改事件注册。另外,如果我们希望移除读事件的同时也移除写事件等,可以使用ALL_EVENTS_MASK。引用[1]还提到,在显式拆除时可以避免调用handle_close方法:reactor->remove_handler(handler,ACE_Event_Handler::DONT_CALL);但是,注意上面的remove_handler版本有两个参数(句柄和掩码)的版本,它默认会调用handle_close(除非指定DONT_CALL)。然而,当我们移除特定事件(不是整个处理器)时,不会调用handle_close。因为handle_close是在整个事件处理器被移除时才调用的。根据ACE文档:当使用remove_handler(handle,mask)时,反应器会从反应器的内部表中移除指定的事件类型,但不会删除事件处理器对象,也不会调用handle_close。只有当移除整个事件处理器(即使用ALL_EVENTS_MASK或者使用remove_handler(handler))时,才会调用handle_close(除非指定了DONT_CALL)。因此,如果只是移除READ_MASK,那么不会调用handle_close,事件处理器对象仍然存在(可能还处理其他事件)。总结:-注销READ_MASK事件:调用remove_handler(handle,ACE_Event_Handler::READ_MASK)-这不会导致handle_close被调用,也不会影响其他事件。用户可能需要根据实际场景选择方法。注意:在移除事件后,如果事件处理器不再需要,用户应该负责删除它(如果它是动态分配的)?但通常,事件处理器对象的管理由应用负责。反应器不会自动删除事件处理器,除非在移除整个处理器时(且没有指定DONT_CALL)在handle_close中删除自己。在引用[3]的示例中,在handle_input中返回-1会导致整个事件处理器被拆除(包括调用handle_close)。在那个示例中,接受器在每次接受一个连接后就把自己移除了,这显然不是常见的做法。常见的是接受器持续监听,而每个连接创建一个新的事件处理器。所以那个示例可能只是为了演示,实际应用可能不同。因此,针对用户的问题,我们给出显式移除READ_MASK的代码示例。注意:以上内容基于引用和ACE的常规用法。由于ACE版本和具体实现可能有差异,建议用户参考官方文档。相关问题:1.在ACE反应器中,如何注册事件处理器?2.事件处理器中的handle_close方法有什么作用?3.如何正确管理ACE_Event_Handler的生命周期?4.在移除事件处理器时,DONT_CALL标志的具体影响是什么?</think>### 如何注销 ACE_Event_Handler 中的 READ_MASK 事件 在 ACE 框架中注销 `READ_MASK` 事件主要有两种方法,核心是通过 `ACE_Reactor::remove_handler()` 实现。以下是具体方法和代码示例: --- #### **方法 1:显式注销(推荐)** 直接调用反应器的 `remove_handler()` 方法注销指定事件: ```cpp // 在事件处理器类中 void unregister_read_event() { // 获取当前句柄和反应器实例 ACE_HANDLE handle = this->get_handle(); ACE_Reactor* reactor = ACE_Reactor::instance(); // 注销 READ_MASK 事件 reactor->remove_handler( handle, // 目标句柄 ACE_Event_Handler::READ_MASK // 指定事件类型 ); } ``` **关键参数说明**: - `handle`:通过 `get_handle()` 获取的事件关联句柄(如 socket) - `READ_MASK`:明确指定注销读事件 - **默认行为**:调用 `handle_close()` 清理资源(可通过参数禁用) --- #### **方法 2:隐式自动注销** 在 `handle_input()` 方法中返回负值触发自动注销: ```cpp // 在事件处理器的读回调中 int handle_input(ACE_HANDLE handle) override { // 业务逻辑处理... if (need_unregister) { return -1; // 返回值 <0 触发自动注销 } return 0; // 继续保留事件监听 } ``` **注意**:此方法会触发 `handle_close()` 并**完全移除整个事件处理器**(不限于 `READ_MASK`)[^1]。 --- #### **完整示例代码** ```cpp class My_Handler : public ACE_Event_Handler { public: ACE_HANDLE get_handle() const override { return socket_.get_handle(); // 返回关联的socket句柄 } int handle_input(ACE_HANDLE handle) override { char buffer[1024]; ssize_t n = socket_.recv(buffer, sizeof(buffer)); if (n <= 0) { unregister_read_event(); // 显式注销读事件 return 0; } // 处理数据... return 0; } // 显式注销 READ_MASK void unregister_read_event() { ACE_Reactor::instance()->remove_handler( get_handle(), ACE_Event_Handler::READ_MASK ); } private: ACE_SOCK_Stream socket_; }; ``` --- #### **关键注意事项** 1. **选择性注销**: - 显式调用 `remove_handler(handle, READ_MASK)` 仅注销读事件,其他事件(如 `WRITE_MASK`)不受影响。 - 隐式返回 `-1` 会移除**所有事件**并销毁处理器。 2. **资源清理**: - 默认调用 `handle_close()` 释放资源,可通过添加 `DONT_CALL` 标志跳过: ```cpp reactor->remove_handler(handle, READ_MASK | ACE_Event_Handler::DONT_CALL); ``` 3. **线程安全**: - 在 `handle_*` 方法内部调用 `remove_handler()` 是安全的,反应器已处理同步[^2]。 --- ### 相关问题 1. **事件注销后如何重新注册读事件?** 需重新调用 `reactor->register_handler(handler, READ_MASK)`。 2. **`handle_close()` 方法的作用和实现规范?** 用于资源清理,反应器在注销时自动调用(除非显式禁用)[^1]。 3. **如何区分注销单一事件与完整事件处理器?** `remove_handler(handle, READ_MASK)` 仅注销读事件;`remove_handler(handler)` 注销整个处理器。 4. **ACE_Reactor 在多线程环境下的注销安全问题?** 反应器内部使用锁保证线程安全,但需避免在回调外直接操作句柄[^2]。 [^1]: 隐式自动拆除或显式拆除均会触发 `handle_close()` 进行资源清理。 [^2]: 反应器在回调期间已锁定,事件处理器方法内操作是安全的。 [^3]: 事件处理器需正确实现 `get_handle()` 以关联目标句柄。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值