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

来源:互联网 发布:淘宝怎么看上架的时间 编辑:程序博客网 时间:2024/05/01 06:51
转载于:http://www.cnblogs.com/TianFang/archive/2006/12/18/595938.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对象根据服务器的具体功能实现,其处理过程和客户端程序类似,注册相应的回调事件并分发即可。

代码如下:

  1 #include <ace/OS.h>  2 #include <ace/Reactor.h>  3 #include <ace/SOCK_Connector.h>   4 #include <ace/SOCK_Acceptor.h>   5 #include <ace/Auto_Ptr.h>  6   7 class ClientService : public ACE_Event_Handler  8 {  9 public: 10     ACE_SOCK_Stream &peer (void) { return this->sock_; } 11  12     int open (void) 13     { 14         //注册读就绪回调函数 15         return this->reactor ()->register_handler(this, ACE_Event_Handler::READ_MASK); 16     } 17  18     virtual ACE_HANDLE get_handle (void) const { return this->sock_.get_handle (); } 19  20     virtual int handle_input (ACE_HANDLE fd ) 21     { 22         //一个简单的EchoServer,将客户端的信息返回 23         int rev = peer().recv(buf,100); 24         if(rev<=0) 25             return -1; 26  27         peer().send(buf,rev); 28         return 0; 29     } 30  31     // 释放相应资源 32 virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask mask) 33     { 34         if (mask == ACE_Event_Handler::WRITE_MASK) 35             return 0; 36         mask = ACE_Event_Handler::ALL_EVENTS_MASK | 37             ACE_Event_Handler::DONT_CALL; 38         this->reactor ()->remove_handler (this, mask); 39         this->sock_.close (); 40         delete this;    //socket出错时,将自动删除该客户端,释放相应资源 41         return 0; 42     } 43  44 protected: 45     char buf[100]; 46     ACE_SOCK_Stream sock_; 47 }; 48  49 class ClientAcceptor : public ACE_Event_Handler 50 { 51 public: 52     virtual ~ClientAcceptor (){this->handle_close (ACE_INVALID_HANDLE, 0);} 53  54     int open (const ACE_INET_Addr &listen_addr) 55     { 56         if (this->acceptor_.open (listen_addr, 1) == -1) 57         { 58             ACE_OS::printf("open port fail"); 59             return -1; 60         } 61         //注册接受连接回调事件 62         return this->reactor ()->register_handler(this, ACE_Event_Handler::ACCEPT_MASK); 63     } 64  65     virtual ACE_HANDLE get_handle (void) const 66     { return this->acceptor_.get_handle (); } 67  68     virtual int handle_input (ACE_HANDLE fd ) 69     { 70         ClientService *client = new ClientService(); 71         auto_ptr<ClientService> p (client); 72  73         if (this->acceptor_.accept (client->peer ()) == -1) 74         { 75             ACE_OS::printf("accept client fail"); 76             return -1; 77         } 78         p.release (); 79         client->reactor (this->reactor ()); 80         if (client->open () == -1) 81             client->handle_close (ACE_INVALID_HANDLE, 0); 82         return 0; 83     } 84      85     virtual int handle_close (ACE_HANDLE handle, 86         ACE_Reactor_Mask close_mask) 87     { 88         if (this->acceptor_.get_handle () != ACE_INVALID_HANDLE) 89         { 90             ACE_Reactor_Mask m = ACE_Event_Handler::ACCEPT_MASK | 91                 ACE_Event_Handler::DONT_CALL; 92             this->reactor ()->remove_handler (this, m); 93             this->acceptor_.close (); 94         } 95         return 0; 96     } 97  98 protected: 99     ACE_SOCK_Acceptor acceptor_;100 };101 102 int main(int argc, char *argv[]) 103 {104     ACE_INET_Addr addr(3000,"192.168.1.142");105     ClientAcceptor server;106     server.reactor(ACE_Reactor::instance());107     server.open(addr);108 109     while(true)110     {111         ACE_Reactor::instance()->handle_events(); 112     }113 114     return 0; 115 }

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

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