ACE中ACE_SOCK下ACE_SOCK_Acceptor类解析

来源:互联网 发布:js apply原理 编辑:程序博客网 时间:2024/06/16 10:49

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()函数的源代码:

intACE_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()函数,我们来看它的定义:

intACE_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的):

intACE_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是空)        将地址的端口号设为0else        将我们的非空地址的指针传进来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,很强大的一个类。

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

0 0
原创粉丝点击