ACE研读笔记之二-Socket Wrapper Facades

C++主要是通过socket APIs 进行网络编程的, socket相关的API接口函数可谓洋洋大观, 多且繁杂, 稍不注意,就有可能误用

用C++类对它们进行适当的封装是不错的主意, 在ACE中对此进行了比较优雅的封装

ACE 的Socket 包装类可分为三类
1. 被动和主动连接工厂类Passive and active conneciton factories:
ACE_SOCK_Acceptor,
ACE_SOCK_Connector

2.数据流类Streaming classes:
ACE_SOCK_Stream , ACE_SOCK_IO

3.地址类Addressing classes:
ACE_Addr, ACE_INET_Addr

以一个简单的HTTP客户端程序为例

#include  " ace/INET_Addr.h "
#include 
" ace/SOCK_Connector.h "
#include 
" ace/SOCK_Stream.h "
#include 
< iostream >
using   namespace  std;

int  main( int  argc,  char   * argv[])
{
 
const   char *  pathname = argc > 1 ? argv[ 1 ]: " index.html " ;
 
const   char *  server_hostname = argc > 2 ? argv[ 2 ]: " www.w3c.org " ;
 printf(
" %s %s %s... " ,argv[ 0 ],pathname,server_hostname);
 ACE_SOCK_Connector connector;
 ACE_SOCK_Stream peer;
 ACE_INET_Addr peer_addr;

 
if (peer_addr. set ( 80 ,server_hostname) ==- 1 )
 
{
  
return   1 ;
 }


 ACE_Time_Value timeout(
20 );
 
if (connector.connect(peer,peer_addr, & timeout) ==- 1 )
 
{
  
if (errno == ETIME)
   cout
<< " connet time out " << endl;
  
return   1 ;
 }

/*
   struct iovec{
     u_long iov_len
     char *iov_base
 }
*/

 
char  buf[ 4096 ];
 iovec iov[
3 ];
 iov[
0 ].iov_base = const_cast < char *> ( " GET " );
 iov[
0 ].iov_len = 4 ;

 iov[
1 ].iov_base = const_cast < char *> (pathname);
 iov[
1 ].iov_len = strlen(pathname); 
  
 iov[
2 ].iov_base = const_cast < char *> ( " HTTP/1.0 " );
 iov[
2 ].iov_len = 13 ;

 
if (peer.sendv_n(iov, 3 ) ==- 1 )
  
return   1 ;

 
for (ssize_t n;(n = peer.recv(buf, sizeof  buf)) > 0 ;)
 
{
  ACE::write_n(ACE_STDOUT,buf,n);
 }

 
return  peer.close() ==- 1 ? 1 : 0 ;
}

编译
g++ -o connectortest connectortest.cpp  -I/home/walter/ACE_wrappers -I./ -L/home/walter/ACE_wrappers/ace -lACE  -ldl -lnsl

代码非常简单清晰, 看不到任何复杂的socket函数调用,其中主要用到了
ACE_SOCK_Connector,ACE_SOCK_Stream,ACE_INET_Addr类

传统上,假如我们直接调用系统的API连接一个网络服务,我们会这样写
1. 创建socket
such as: socket(AF_INET, SOCK_STREAM, 0)

2. 设置socket option
such as: setsockopt(nSock, SOL_SOCKET, SO_REUSEADDR, &socket_option_value, sizeof(socket_option_value));

3. 设置socket address/port
主要是设置 struct sockaddr_in的sin_addr,sin_port为相应的网络地址和端口

4. 进行连接connect
such as: connect(nSock,(struct sockaddr *)&saddr, sizeof(saddr));

5. 进行数据传输send/recv

ACE的connector基本上也是这个步骤,不过它进行了一些巧妙的封装, 并加上了超时和错误的处理,提供了跨平台的实现, 它的connect方法只是依次调用了
1. ACE_SOCK_Connector::shared_open
2. ACE_SOCK_Connector::shared_connect_start
3. ACE_OS::connect
4. ACE_SOCK_Connector::shared_connect_finish

int
ACE_SOCK_Connector::connect (ACE_SOCK_Stream 
& new_stream,
                             
const  ACE_Addr  & remote_sap,
                             
const  ACE_Time_Value  * timeout,
                             
const  ACE_Addr  & local_sap,
                             
int  reuse_addr,
                             
int   /*  flags  */ ,
                             
int   /*  perms  */ ,
                             
int  protocol)
{
  ACE_TRACE (
" ACE_SOCK_Connector::connect " );

  
if  ( this -> shared_open (new_stream,
                         remote_sap.get_type (),
                         protocol,
                         reuse_addr) 
==   - 1 )
    
return   - 1 ;
  
else   if  ( this -> shared_connect_start (new_stream,
                                       timeout,
                                       local_sap) 
==   - 1 )
    
return   - 1 ;

  
int  result  =  ACE_OS::connect (new_stream.get_handle (),
                                reinterpret_cast
< sockaddr  *>  (remote_sap.get_addr ()),
                                remote_sap.get_size ());

  
return   this -> shared_connect_finish (new_stream,
                                      timeout,
                                      result);
}


shared_open方法其实是调用ACE_SOCK_Stream的open方法
类ACE_SOCK_Stream的继承关系如下
ACE_SOCK_Stream--->ACE_SOCK_IO-->ACE_SOCK-->ACE_IPC_SAP
而ACE_SOCK_Stream的open方法是从ACE_SOCK继承下来的,就是对socket, setsockopt调用的封装 

 

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 ;
}

(To be continued...)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值