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

本文介绍使用Reactor模式在服务器端实现客户端连接处理的方法。文章详细解释了ClientAcceptor和ClientService两个核心组件的作用及其实现代码。通过示例代码展示了如何利用ACE库进行事件注册、处理客户端连接及数据交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本贴转自http://www.cnblogs.com/TianFang/category/78013.html  作者:天方

 

在服务器端使用Reactor框架

使用Reactor框架的服务器端结构如下:

服务器端注册两种事件处理器,ClientAcceptor和ClientService ,ClientService类负责和客户端的通信,每一个ClientService对象对应一个客户端的Socket连接。 ClientAcceptor专门负责被动接受客户端的连接,并创建ClientService对象。这样,在一个N个Socket连接的服务器程序中,将存在1个ClientAcceptor对象和N个ClientService对象。

整个服务器端流程如下:

  1. 首先创建一个ClientAcceptor对象,该对象在Reactor上注册ACCEPT_MASK事件,Reactor将自动在监听端口建立Socket监听。
  2. 如果有对该端口的Socket连接时,Reactor将自动回调handle_input方法,ClientAcceptor重载此方法,并创建一个ClientService对象,用于处理和Client的通信。
  3. ClientService对象根据服务器的具体功能实现,其处理过程和客户端程序类似,注册相应的回调事件并分发即可。

代码如下:

#include <ace/OS.h>
#include <ace/Reactor.h>
#include <ace/SOCK_Connector.h>
#include <ace/SOCK_Acceptor.h>
#include <ace/Auto_Ptr.h>

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

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

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

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

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

    // 释放相应资源
virtual int 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 ();
        delete this ;    //socket出错时,将自动删除该客户端,释放相应资源
        return 0;
    }

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

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;
        }
        //注册接受连接回调事件
        return this ->reactor ()->register_handler(this , ACE_Event_Handler::ACCEPT_MASK);
    }

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

    virtual int 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;
    }
    
    virtual int 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_;
};

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;
}

代码功能比较简单,需要注意以下几点:

  1. 这里注册事件的方式和前面的文章中方式不一样,是通过ACE_Event_Handler类的reactor() 方法设置和获取reactor的指针,比较直观和方便。前面的文章是通过ACE_Reactor::instance()来获取的一个单体reactor的指针。
  2. 当客户端Socket连接关闭时,需要释放相应资源 ,需要注意一下ClientService对象的handle_close方法中释放资源的相应代码。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值