接受器/连接器模式设计用于降低连接建立与连接建立后所执行的服务之间的耦合。例如,在WWW浏览器中,所执行的服务或“实际工作”是解析和显示客户浏览器接收到的HTML页面。连接建立是次要的,可能通过BSDsocket或其他一些等价的IPC机制来完成。使用这些模式允许程序员专注于“实际工作”,而最少限度地去关心怎样在服务器和客户之间建立连接。而另外一方面,程序员也可以独立于他所编写的、或将要编写的服务例程,去调谐连接建立的策略。
因为该模式降低了服务和连接建立方法之间的耦合,非常容易改动其中一个,而不影响另外一个,从而也就可以复用以前编写的连接建立机制和服务例程的代码。在同样的例子中,使用这些模式的浏览器程序员一开始可以构造他的系统、使用特定的连接建立机制来运行它和测试它;然后,如果先前的连接机制被证明不适合他所构造的系统,他可以决定说他希望将底层连接机制改变为多线程的(或许使用线程池策略)。因为此模式提供了严格的去耦合,只需要极少的努力就可以实现这样的变动。
ACE_Acceptor 工厂允许应用开发者改变“助手”对象,以用于:
被动连接建立
连接建立后的处理
下面是一个很简单的例子:
#include ”ace/Reactor.h”
#include ”ace/Svc_Handler.h”
#include ”ace/Acceptor.h”
#include ”ace/Synch.h”
#include ”ace/SOCK_Acceptor.h”
class My_Svc_Handler:
public ACE_Svc_Handler <ACE_SOCK_STREAM,ACE_NULL_SYNCH>
{
public:
int open(void*)
{
cout<<”Connection established”<<endl;
}
};
typedef ACE_Acceptor<My_Svc_Handler,ACE_SOCK_ACCEPTOR> MyAcceptor;
int main(int argc, char* argv[])
{
ACE_INET_Addr addr(PORT_NUM);
MyAcceptor acceptor(addr, ACE_Reactor::instance());
while(1)
ACE_Reactor::instance()->handle_events();
}
这样就是一个简单的服务器,只能接收连接的一个服务器,当连接建立后,open()函数会被回调。是不是很神奇,我们就来看一下ACE_Acceptor类的源码。
首先ACE_Acceptor是个模板类,需要两个类,可以看到我们例子中的是
一个是我们自己定义的处理服务类和ACE_SOCK__Acceptor类,这两个类告诉工厂,我们需要一个接受SOCK连接的接受器,并且接受器接受连接后用我们定义的类的对象来处理这个连接。
构造函数:
template <typename SVC_HANDLER, typename PEER_ACCEPTOR>
ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::ACE_Acceptor
(const typename PEER_ACCEPTOR::PEER_ADDR &addr,
ACE_Reactor *reactor,
int flags,
int use_select,
int reuse_addr)
{
ACE_TRACE ("ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::ACE_Acceptor");
**if (this->open (addr,
reactor,
flags,
use_select,
reuse_addr) == -1)**
ACELIB_ERROR ((LM_ERROR,
ACE_TEXT ("%p\n"),
ACE_TEXT ("ACE_Acceptor::ACE_Acceptor")));
}
看着是不是头晕?那么多的参数,其实很简单,这个是函数的定义,我们看一下它的声明:
ACE_Acceptor (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr,
ACE_Reactor *reactor = ACE_Reactor::instance (),
int flags = 0,
int use_select = 1,
int reuse_addr = 1);
发现后4个参数都是有默认值的,一般情况下,我们只需要一个参数就可以了,是不是送了一大口气。那么这些参数都是干什么的呢?
local_addr:表示一个地址,因为我们讨论的是SOCK问题,所以传递的 是一个ACE_INET_Addr类的对象。
reactor:这个指针指向一个反应器,这个反应器就是用来注册事件,表示我们使用的反应器对象,一般情况下,默认就好,也最好不要改
flags:用来开关阻塞与非阻塞,默认为阻塞,如果设置为ACE_NONBLOCK,即为分阻塞
resure_addr:我们的接受器的open()函数的第二个参数,以后会用到,本例为ACE_SOCK_Acceptor::open()函数。
我们回到函数定义中,我们可以发现,最重要的就是一个open()函数的调用,这个函数又是做了什么呢?
这次我们先看其声明:
virtual int open (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr,
ACE_Reactor *reactor = ACE_Reactor::instance (),
int flags = 0,
int use_select = 1,
int reuse_addr = 1);
我们可以发现,参数和构造函数一样,参数的意义就不说了,当然有人可能也发现了这个函数是个virtual函数,我们可以在子类中重写这个函数。很多函数都是可以重写的。但是我们这里不讨论这个。
现在回到正题,这个函数干了什么事情呢?下面是它的定义:
template <typename SVC_HANDLER, typename PEER_ACCEPTOR> int
ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::open
(const typename PEER_ACCEPTOR::PEER_ADDR &local_addr,
ACE_Reactor *reactor,
int flags,
int use_select,
int reuse_addr)
{
ACE_TRACE ("ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::open");
this->flags_ = flags;