ACE_Acceptor类源码浅解析

ACE_Acceptor类是接受器模式的实现,用于降低连接建立与服务之间的耦合。通过源码分析,了解到它如何进行被动连接建立、连接后的处理,以及如何通过ACE_Reactor注册事件,当有连接时调用handle_input()处理。ACE_Acceptor的open()函数完成了bind()、listen()和accept()操作,并创建对象处理连接。在错误发生时,通过ACE_Svc_Handler的handle_close()函数进行资源回收。

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

接受器/连接器模式设计用于降低连接建立与连接建立后所执行的服务之间的耦合。例如,在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;
  this->use_select_ = use_select;
  this->reuse_addr_ = reuse_addr;
  this->peer_acceptor_addr_ = local_addr;

  // Must supply a valid Reactor to Acceptor::open()...

  if (reactor == 0)
    {
      errno = EINVAL;
      return -1;
    }

  // Open the underlying PEER_ACCEPTOR.
  **if (this->peer_acceptor_.open (local_addr, reuse_addr) == -1)**//欢迎你回到这里,谢谢你能坚持的看到最后前一点
    return -1;

  // Set the peer acceptor's handle into non-blocking mode.  This is a
  // safe-guard against the race condition that can otherwise occur
  // between the time when <select> indicates that a passive-mode
  // socket handle is "ready" and when we call <accept>.  During this
  // interval, the client can shutdown the connection, in which case,
  // the <accept> call can hang!
  (void) this->peer_acceptor_.enable (ACE_NONBLOCK);

  **int const result = reactor->register_handler (this,
                                                ACE_Event_Handler::ACCEPT_MASK);**
  if (result != -1)
    this->reactor (reactor);
  else
    this->peer_acceptor_.close ();

  return result;
}

很长的代码,我们只关心最主要的,这里它调用了两个函数,我们不关心他们返回值的处理,在这里他们都是成功的。
这两个函数干了很多的事情。从前往后:

if (this->peer_acceptor_.open (local_addr, reuse_addr) == -1)
    return -1;

这个peer_acceptor_又是什么呢?
其实这个是一个 ACE_SOCK_Acceptor的对象,当然是看你传递的模板的参数是什么,我们本例子中为这个对象,这是ACE_Acceptor类的成员变量,这个其实就是具体干事情的对象。
可以看到它调用了open()函数,而参数就是我们传递的地址和构造函数的最后一个参数,那么到这里,当这个函数执行完成后,那么绑定和监听这两个动作,接受器已经帮我们自己做了,我们不需要再自己来做这些重复的工作了。

接下来就是第二个函数的调用:

int const result = reactor->register_handler (this,
                                                ACE_Event_Handler::ACCEPT_MASK);

这个函数学过ACE_Reactor的肯定知道,往反应器中注册事件。通过这个函数我们的ACE_Acceptor就往反应器中注册了ACCEPT_MASK这个信号,那么当有这个信号的时候,就会通知我们的接受器,那么就会回调handle_input()函数,但是这个函数应该在ACE_Svc_Handler类或者ACE_Event_Handler等类中,我们传进来的自己的处理类虽然有这个函数,但是那是为了处理连接之后的数据处理,那么这个handle_input()函数在哪里呢?

template <typename SVC_HANDLER, typename PEER_ACCEPTOR> int
ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::handle_input (ACE_HANDLE listener)

我们发现这个函数在ACE_Acceptor这个工厂中有定义,那么到底是不是这个函数呢?
答案肯定是是的,那么为什么会调用这个函数呢?
应该注意到,我们注册函数传递的参数,第一个是一个this指针,就跟我写的那个ACE_Reactor模式的服务器一样,但那个类是继承了ACE_Event_Handler类,所以有handle_input()函数,并且当消息传达到时会调用这个函数,那么我们的ACE_Acceptor类会是这样产生的吗?我们看一下类声明:

template <typename SVC_HANDLER, typename PEER_ACCEPTOR>
class ACE_Acceptor : public ACE_Service_Object

可以看到,不是从那两个类中继承下来的,那么到底是怎么回事呢?

我们来看一下ACE_Server_Object这个类的声明:

class ACE_Export ACE_Service_Object
  : public ACE_Event_Handler,
    public ACE_Shared_Object

可以看到这个类是继承自ACE_Event_Habdler类,那么上面的一切都解释的通了。
回到正题,我们已经知道了,在ACE_Acceptor::open()这个函数中,做了两件事,一件事完成完成了bind()函数和listen()函数的调用,即将套接字连接的准备工作完成,并且注册事件到反应器(Reactor)中,当有连接消息时,那么就会调用handle_input()函数,那么这个函数中做了什么呢?我们还需要什么呢?

我们知道,服务器中,一个监听套接字,然后当连接到来时,创建一个套接字,这个套接字完成通信工作,然后监听套接字继续监听。

这个函数就是完成了这样的工作,连接到达,产生一个对象去处理连接。
直接看代码:

template <typename SVC_HANDLER, typename PEER_ACCEPTOR> int
ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::handle_input (ACE_HANDLE listener)
{
  ACE_TRACE ("ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::handle_input");

  // Default is "timeout (0, 0)," which means "poll."
  ACE_Time_Value timeout;

  // Accept connections from clients.  Note that a loop is used for two
  // reasons:
  //
  // 1. It allows us to accept all pending connections without an
  //    extra trip through the ACE_Reactor and without having to use
  //    non-blocking I/O...
  //
  // 2. It allows the TLI_SAP::ACE_Acceptor class to work correctly (don't
  //    ask -- TLI is *horrible*...).

  // Ensure that errno is preserved in case the ACE::handle_read_ready()
  // method resets it in the loop bellow. We are actually supposed to
  // ignore any errors from this loop, hence the return 0 following it.
  ACE_Errno_Guard error (errno);

  // @@ What should we do if any of the substrategies fail?  Right
  // now, we just print out a diagnostic message if <ACE::debug>
  // returns > 0 and return 0 (which means that the Acceptor remains
  // registered with the Reactor)...
  do
    {
      // Create a service handler, using the appropriate creation
      // strategy.

      **SVC_HANDLER *svc_handler = 0;**

      if (**this->make_svc_handler (svc_handler)** == -1)
        {
          if (ACE::debug ())
            {
              ACELIB_DEBUG ((LM_DEBUG,
                          ACE_TEXT ("%p\n"),
                          ACE_TEXT ("make_svc_handler")));
            }
          return 0;
        }
      // Accept connection into the Svc_Handler.
      else if (**this->accept_svc_handler (svc_handler)** == -1)
        {
          // Note that <accept_svc_handler> closes the <svc_handler>
          // on failure.
          if (ACE::debug ())
            {
              ACELIB_DEBUG ((LM_DEBUG,
                          ACE_TEXT ("%p\n"),
                          ACE_TEXT ("accept_svc_handler")));
            }
          const int ret = this->handle_accept_error ();
          if (ret == -1)
            {
              // Ensure that the errno from the above call propegates.
              error = errno;
            }
          return ret;
        }
      // Activate the <svc_handler> using the designated concurrency
      // strategy (note that this method becomes responsible for
      // handling errors and freeing up the memory if things go
      // awry...).
      else if (**this->activate_svc_handler (svc_handler)**** == -1)
        {
          // Note that <activate_svc_handler> closes the <svc_handler>
          // on failure.

          if (ACE::debug ())
            {
              ACELIB_DEBUG ((LM_DEBUG,
                          ACE_TEXT ("%p\n"),
                          ACE_TEXT ("activate_svc_handler")));
            }
          return 0;
        }
      // Now, check to see if there is another connection pending and
      // break out of the loop if there is none.
    } while (this->use_select_ &&
             ACE::handle_read_ready (listener, &timeout) == 1);
  return 0;
}

是不是又被代码吓晕了,但是去掉注释真的就没有什么东西了。而且,我们直关注我们关注的地方。

其中有一个do while循环,这个循环中做了这个函数最该做的事,完成了它该干的事,就在三个if语句中。
循环中有第一句if代码:

SVC_HANDLER *svc_handler = 0;

      if (this->make_svc_handler (svc_handler) == -1)
        {
          if (ACE::debug ())
            {
              ACELIB_DEBUG ((LM_DEBUG,
                          ACE_TEXT ("%p\n"),
                          ACE_TEXT ("make_svc_handler")));
            }
          return 0;
        }

SVC_HANDLER 类型就是我们给这个工厂类的第一个参数,实际就是我们的处理数据的类,这个例子中为My_Svc_Handler类型,这里申请了这样一个指针,并且将指针传给了make_svc_handler()这个函数,这个函数对这个指针做了些什么呢?下面为这个函数的源码:

template <typename SVC_HANDLER, typename PEER_ACCEPTOR> int
ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::make_svc_handler (SVC_HANDLER *&sh)
{
  ACE_TRACE ("ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::make_svc_handler");

  **if (sh == 0)
    ACE_NEW_RETURN (sh,
                    SVC_HANDLER,
                    -1);**

  // Set the reactor of the newly created <SVC_HANDLER> to the same
  // reactor that this <ACE_Acceptor> is using.
  sh->reactor (this->reactor ());
  return 0;
}

这个函数最主要的地方,就是ACE_NEW_RETURN这个宏,这个宏又是个什么呢?

#    define ACE_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL) \
   do { POINTER = new (ACE_nothrow) CONSTRUCTOR; \
     if (POINTER == 0) { errno = ENOMEM; return RET_VAL; } \
   } while (0)

是不是也看不懂,但是我们也不需要看懂,我们只要知道里面有一个new运算,申请了一个CONSTRUCTOR这样类型的对象的内存,而这个类型我们传递的是SVC_HANDLER,这个类型已经解释很多了。 ACE_nothrow并不是一个强转,它实际上是std::nothrow吗,这个东西的意思是当内存不足时,将指针置为NULL。

第二个if语句干了什么呢?它调用了accept_svc_handler ()函数,这个函数完成了什么呢?下面是源码

template <typenaSVC_HANDLER, typename PEER_ACCEPTOR> int
ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::accept_svc_handler
  (SVC_HANDLER *svc_handler)
{
  ACE_TRACE ("ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::accept_svc_handler");

  // Try to find out if the implementation of the reactor that we are
  // using requires us to reset the event association for the newly
  // created handle. This is because the newly created handle will
  // inherit the properties of the listen handle, including its event
  // associations.

  ACE_Reactor *reactor = this->reactor ();
  bool reset_new_handle;

  if (reactor)
    {
      reset_new_handle = reactor->uses_event_associations ();
    }
  else
    {
      // Acceptor is closed, so reject this call
      errno = EINVAL;
      return -1;
    }

  if (**this->acceptor ().accept (svc_handler->peer (), // stream
                                0, // remote address
                                0, // timeout
                                true, // restart
                                reset_new_handle  // reset new handler
                                ) == -1)**
    {
      // Ensure that errno is preserved in case the svc_handler
      // close() method resets it
      ACE_Errno_Guard error(errno);

      // Close down handler to avoid memory leaks.
      svc_handler->close (CLOSE_DURING_NEW_CONNECTION);

      return -1;
    }
  else
    return 0;
}

我们看到,accept()函数是有this->acceptor()这个函数的返回值返回的,这个函数的源代码我就不粘贴了,我之粘贴它的返回值:

return const_cast<PEER_ACCEPTOR &> (this->peer_acceptor_);

返回的是peer_acceptor_,而这个变量就是这个类中的私有变量,就是我们前面构造函数中的open()中调用的其自身open()的那个对象,可以去前面查看。我做了标记。这样到这里为止,bind(),listen(),accept()这三个函数已经调用完了。我们的监听套接子已经完成了。

那么第三句if语句调用了activate_svc_handler(),这个函数干了什么呢?下面是源码:

template <typename SVC_HANDLER, typename PEER_ACCEPTOR> int
ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::activate_svc_handler
  (SVC_HANDLER *svc_handler)
{
  ACE_TRACE ("ACE_Acceptor<SVC_HANDLER, PEER_ACCEPTOR>::activate_svc_handler");

  int result = 0;

  // See if we should enable non-blocking I/O on the <svc_handler>'s
  // peer.
  if (ACE_BIT_ENABLED (this->flags_,
                       ACE_NONBLOCK))
    {
      if (svc_handler->peer ().enable (ACE_NONBLOCK) == -1)
        result = -1;
    }
  // Otherwise, make sure it's disabled by default.
  else if (svc_handler->peer ().disable (ACE_NONBLOCK) == -1)
    result = -1;

  if (result == 0 && **svc_handler->open ((void *) this)** == -1)
    result = -1;

  if (result == -1)
    // The connection was already made; so this close is a "normal" close
    // operation.
    svc_handler->close (NORMAL_CLOSE_OPERATION);

  return result;
}

一句句的解释,我也没看懂,但我们只需要关心我们需要的。
可以看到这句话svc_handler->open ((void *) this)这个参数我们不需要管,这个函数调用了open()函数,而且还是用svc_handler这个指针,那么到这里,我们就应该能明白了为什么连接建立后,会调用我们的自己写的类的open()函数了吧,这个函数中我们需要做的就是注册事件,做一些通信的准备工作。

那么到这里为止,我们所关心的所有东西几乎都已经从源码中看到了,是不是心中有个疑问,既然对象是new出来的,那么delete在哪里呢?

其实delete没有在ACE_Acceptor这个类中,而在ACE_Svc_Handler这个类中,我们知道如果handle_input()等这些函数出错返回-1的话,会调用handle_close()这个函数,来看下源码:

template <typename PEER_STREAM, typename SYNCH_TRAITS> int
ACE_Svc_Handler<PEER_STREAM, SYNCH_TRAITS>::handle_close (ACE_HANDLE,
                                                       ACE_Reactor_Mask)
{
  ACE_TRACE ("ACE_Svc_Handler<PEER_STREAM, SYNCH_TRAITS>::handle_close");

  if (this->reference_counting_policy ().value () ==
      ACE_Event_Handler::Reference_Counting_Policy::DISABLED)
    {
      **this->destroy ();**
    }

  return 0;
}

这个函数中调用了destory()函数来进行收尾,这个destory()又是怎样的呢?

template <typename PEER_STREAM, typename SYNCH_TRAITS> void
ACE_Svc_Handler<PEER_STREAM, SYNCH_TRAITS>::destroy (void)
{
  ACE_TRACE ("ACE_Svc_Handler<PEER_STREAM, SYNCH_TRAITS>::destroy");

  // Only delete ourselves if we're not owned by a module and have
  // been allocated dynamically.
  if (this->mod_ == 0 && this->dynamic_ && this->closing_ == false)
    // Will call the destructor, which automatically calls <shutdown>.
    // Note that if we are *not* allocated dynamically then the
    // destructor will call <shutdown> automatically when it gets run
    // during cleanup.
    **delete this;**
}

我们的delete出来了,就是在这里将资源回收的,当然这个destory()很多地方都会调用,析构函数啊等等,好了,源码的简单解析写完了,好累,希望对你们有所帮助。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值