ACE中ACE_SOCK下ACE_SOCK_Acceptor类解析

原创 2015年11月20日 21:02:50

ACE_SOCK_Acceptor,ACE中面对流(有连接)sock编程的接受器类,将服务器端编程的细节,步骤做了包装,让我们不需要再直接的使用OS的复杂,繁多的API函数,那么这个类中到底替我们做了多少呢?我们该如何修改它呢?

首先看类的构造函数:

ACE_SOCK_Acceptor (void);

ACE_SOCK_Acceptor (const ACE_Addr &local_sap,
                     int reuse_addr = 0,
                     int protocol_family = PF_UNSPEC,
                     int backlog = ACE_DEFAULT_BACKLOG,
                     int protocol = 0);
ACE_SOCK_Acceptor (const ACE_Addr &local_sap,
                     ACE_Protocol_Info *protocolinfo,
                     ACE_SOCK_GROUP g,
                     u_long flags,
                     int reuse_addr,
                     int protocol_family = PF_UNSPEC,
                     int backlog = ACE_DEFAULT_BACKLOG,
                     int protocol = 0);

第三个构造函数比第二个多了三个参数,这个构造函数我们不讨论(超复杂,相信你知道真相也会放弃的)。

第一个是无参,不解释。

第二个构造函数,也是重点,它有5个参数,但是后四个都有默认的参数,但是还是解释一下它们的含义。

local_sap:类型是ACE_Addr的引用,不用说了吧,bind()函数的地址参数
reuse_addr:这个参数表示是否打开SO_REUSEPORT这个选项,至于这个选项的含义很长的,这里给你一个链接:http://www.cnblogs.com/mydomain/archive/2011/08/23/2150567.html       讲的很详细。

protocol_family:就是sock函数的第1个参数,地址族,默认就好
backlog:这个是listen()函数的第二个参数,意义就不说了
protocol:sock()函数的第3个参数,这个参数最好不要改,让系统自己确定使用的协议就好,当然默认是TCP

接下来是两个open()函数,这两个函数的参数分别对应两个构造函数,连参数都是一样的,实际上两个构造函数内部就是调用这两个自己对应的open()函数来完成的,当然如果你使用的无参构造函数,那么这个open()函数你还是仔细写一下。

/// Close the socket.  Returns 0 on success and -1 on failure.
  int close (void);

关闭函数,很简单。

接下来就是两个accept()函数,也是重中之重,第二个不说了,因为它要就在windows中才有可能用到。

int accept (ACE_SOCK_Stream &new_stream,
              ACE_Addr *remote_addr = 0,
              ACE_Time_Value *timeout = 0,
              bool restart = true,
              bool reset_new_handle = false) const;

解释一下参数的意义:

new_stream:代表一个通信对象,服务器将通过这个对象与服务器来通信,简单的说,就是用这个对象来调用sendrecv等函数来进行通信的
remote_addr:请求连接的客户端的地址
timeout:设置超时时间,0(NULL)就是阻塞模式,传入timeout(0,0)代表等待0s,也就是非阻塞模式(多好,连超时都设置好了)
restart:这个参数代表党accept调用被某些原因中断后,会自动重启accept函数

最后一个参数很麻烦,最后一个参数,意味着很少的情况才会修改它,或者说不鼓励你去修改它,默认就好

在这个类中,其实就两个函数,一个open(),一个accept(),那么我们很容易能猜到,open()中完成了bind()和listen()调用,accept中完成了accept()函数的调用,那么到底是不是呢?
我们先来看一下open()函数的源代码:

int
ACE_SOCK_Acceptor::open (const ACE_Addr &local_sap,
                         int reuse_addr,
                         int protocol_family,
                         int backlog,
                         int protocol)
{
  ACE_TRACE ("ACE_SOCK_Acceptor::open");

  if (local_sap != ACE_Addr::sap_any)
    protocol_family = local_sap.get_type ();
  else if (protocol_family == PF_UNSPEC)
    {
#if defined (ACE_HAS_IPV6)
      protocol_family = ACE::ipv6_enabled () ? PF_INET6 : PF_INET;
#else
      protocol_family = PF_INET;
#endif /* ACE_HAS_IPV6 */
    }

  if (ACE_SOCK::open (SOCK_STREAM,
                      protocol_family,
                      protocol,
                      reuse_addr) == -1)
    return -1;
  else
    return this->shared_open (local_sap,
                              protocol_family,
                              backlog);
}

这里面最重要的就是最后的两个open()函数,前面的一些是确定地址族的判断,可以不用管(当然我用的是默认),我们来看第一个,也就是ACE_SOCK::open()函数,我们来看它的定义:

int
ACE_SOCK::open (int type,
                int protocol_family,
                int protocol,
                int reuse_addr)
{
  ACE_TRACE ("ACE_SOCK::open");
  int one = 1;

  this->set_handle (ACE_OS::socket (protocol_family,
                                    type,
                                    protocol));

  if (this->get_handle () == ACE_INVALID_HANDLE)
    return -1;
  else if (protocol_family != PF_UNIX
           && reuse_addr
           && this->set_option (SOL_SOCKET,
                                SO_REUSEADDR,
                                &one,
                                sizeof one) == -1)
    {
      this->close ();
      return -1;
    }
  return 0;
}

我们可以看到两个我们很熟悉的函数名称,sock()和set_option(),第一个就是sock()函数的包裹函数了,第二个原型就是setsocketopt这个函数,也就是在这里我们设置了SO_REUSEPORT这个选项。

现在sock()函数找到了,还有两个三个函数,会在另外的open()函数中吗?
我们看下另外的一个open()函数的定义:(由于代码过长,我截取了其中的一部分,就是ipv6的那一部分,只看ipv4的):

int
ACE_SOCK_Acceptor::shared_open (const ACE_Addr &local_sap,
                                int protocol_family,
                                int backlog)
{
  ACE_TRACE ("ACE_SOCK_Acceptor::shared_open");
  int error = 0;
  if (protocol_family == PF_INET)
    {
      sockaddr_in local_inet_addr;
      ACE_OS::memset (reinterpret_cast<void *> (&local_inet_addr),
                      0,
                      sizeof local_inet_addr);

      if (local_sap == ACE_Addr::sap_any)
        {
          local_inet_addr.sin_port = 0;
        }
      else
        local_inet_addr = *reinterpret_cast<sockaddr_in *> (local_sap.get_addr ());
      if (local_inet_addr.sin_port == 0)
        {
          if (ACE::bind_port (this->get_handle (),
                              ACE_NTOHL (ACE_UINT32 (local_inet_addr.sin_addr.s_addr))) == -1)
            error = 1;
        }
      else if (ACE_OS::bind (this->get_handle (),
                             reinterpret_cast<sockaddr *> (&local_inet_addr),
                             sizeof local_inet_addr) == -1)
        error = 1;
    }
  else if (ACE_OS::bind (this->get_handle (),
                         (sockaddr *) local_sap.get_addr (),
                         local_sap.get_size ()) == -1)
    error = 1;

  if (error != 0
      || ACE_OS::listen (this->get_handle (),
                         backlog) == -1)
    {
      ACE_Errno_Guard g (errno);    // Preserve across close() below.
      error = 1;
      this->close ();
    }

  return error ? -1 : 0;
}

listen()函数调用应该看的很清楚,但是bind()函数却有很多,我来就是一下这个条件语句:

if   需要bind的地址是个空的地址(就是ACE_INET_Addr是空)
        将地址的端口号设为0
else
        将我们的非空地址的指针传进来
if     
        这个if就省略不说了
else
        就执行我们期望的bind()函数

到现在为止。sock(),bind(),listen()全部都出来了,那么最后一个accept()调用当然就在我们类中的accept()函数中了,但是我们还是来看一下:
int
ACE_SOCK_Acceptor::accept (ACE_SOCK_Stream &new_stream,
ACE_Addr *remote_addr,
ACE_Time_Value *timeout,
bool restart,
bool reset_new_handle) const
{
ACE_TRACE (“ACE_SOCK_Acceptor::accept”);

  int in_blocking_mode = 0;
  if (this->shared_accept_start (timeout,
                                 restart,
                                 in_blocking_mode) == -1)
    return -1;
  else
    {
      // On Win32 the third parameter to <accept> must be a NULL
      // pointer if we want to ignore the client's address.
      int *len_ptr = 0;
      sockaddr *addr = 0;
      int len = 0;

      if (remote_addr != 0)
        {
          len = remote_addr->get_size ();
          len_ptr = &len;
          addr = (sockaddr *) remote_addr->get_addr ();
        }

      do
        new_stream.set_handle (ACE_OS::accept (this->get_handle (),
                                               addr,
                                               len_ptr));
      while (new_stream.get_handle () == ACE_INVALID_HANDLE
             && restart
             && errno == EINTR
             && timeout == 0);

      // Reset the size of the addr, so the proper UNIX/IPv4/IPv6 family
      // is known.
      if (new_stream.get_handle () != ACE_INVALID_HANDLE
          && remote_addr != 0)
        {
          remote_addr->set_size (len);
          if (addr)
            remote_addr->set_type (addr->sa_family);
        }
    }

  return this->shared_accept_finish (new_stream,
                                     in_blocking_mode,
                                     reset_new_handle);
}

里面有三个accept函数,第一个shared_accept_start()函数,这个函数完成了定时功能,第二个accept()函数就是我们期望的,最后的那个函数,第三个shared_accept_finish()函数完成了将句柄(可以理解为文件表示符)与我们传进去的ACE_SOCK_Stream关联起来,完成通信。

ACE_SOCK_Acceptor真的是帮我们做了很多的工作,不需要我们直接操作复杂且难懂的OS的API,很强大的一个类。

希望对看完的你们有帮助。

关于ACE静态库不能使用ACE_SOCK_Acceptor::accpet函数的迷思

同一个函数,同一个头文件,一边实现,一边应用,天经地义, 可昨天就被一个天经地义的问题给难住了。 ACE_SOCK_Acceptor类中一共定义了两个accept函数原型,   int acce...

ACE_SOCK下的几个类

ACE_SOCK_Acceptor  相当于网络编程中的Acceptor  监听客户端的请求。 /* -*- C++ -*- */ //==============================...

ACE_Acceptor类源码浅解析

接受器/连接器模式设计用于降低连接建立与连接建立后所执行的服务之间的耦合。例如,在WWW浏览器中,所执行的服务或“实际工作”是解析和显示客户浏览器接收到的HTML页面。连接建立是次要的,可能通过BSD...

ACE学习之ACE_INET_Addr,ACE_SOCK_Acceptor 源代码

ACE_INET_Addr 用来封装了基本的LINUX Socket的连接。   首先了解一个结构体 struct sockaddr_in { short s...

ACE_SOCK

该类属中的类都位于ACE_SOCK之下;它提供使用BSD socket编程接口的Internet域和UNIX域协议族的接口。这个类属中的类被进一步划分为: Dgram类, Acceptor类和Str...

ACE6测试之ACE_SOCK_Stream2

Connect_to_server()方法使用类型为 ACE_SOCK_Connector 的连接器(connector_)来主动地建立连接。连接的设置通过调用连接器 connector_上的 con...

ACE6测试之ACE_SOCK_Stream

ACE中的流包装提供面向连接的通信。流数据传输包装类包括ACE_SOCK_Stream和ACE_LSOCK_Stream,连接建立类包括针对TCP/IP的ACE_SOCK_Connector和ACE_...

关于ACE_Asynch_Acceptor::accept 内存泄露的问题(Windows)

问题描述 使用ACE_Proactor和ACE_Asynch_Acceptor,开发服务器端侦听客户机的连接功能时,当程序正常逻辑退出时,会发生内存泄露的问题,有时会怀疑ACE的BUG,其实不全是如此...

ACE接受器-连接器设计模式Acceptor-Connector

本贴转自http://www.cnblogs.com/TianFang/category/78013.html  作者:天方   接受器-连接器设计模式(Acceptor-Connector)使分布式...

ACE_Get_Opt参数解析类

#include #include #include using namespace std; void usage() { cout
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:ACE中ACE_SOCK下ACE_SOCK_Acceptor类解析
举报原因:
原因补充:

(最多只允许输入30个字)