您的位置:首页 > Web前端 > React

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

2016-03-08 16:43 501 查看
转载于:/article/4658701.html
在服务器端使用Reactor框架

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

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

整个服务器端流程如下:

首先创建一个ClientAcceptor对象,该对象在Reactor上注册ACCEPT_MASK事件,Reactor将自动在监听端口建立Socket监听。

如果有对该端口的Socket连接时,Reactor将自动回调handle_input方法,ClientAcceptor重载此方法,并创建一个ClientService对象,用于处理和Client的通信。

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 }


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

这里注册事件的方式和前面的文章中方式不一样,是通过ACE_Event_Handler类的reactor()方法设置和获取reactor的指针,比较直观和方便。前面的文章是通过ACE_Reactor::instance()来获取的一个单体reactor的指针。

当客户端Socket连接关闭时,需要释放相应资源,需要注意一下ClientService对象的handle_close方法中释放资源的相应代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: