zoukankan      html  css  js  c++  java
  • ACE Socket Wrapper Facade

    ACE Socket Wrapper Facade

    1:Socket API

    1.1 IPC(进程间通信)

      IPC分为本地IPC(同一计算机上的不同进程)和远程IPC(网络互联的不同计算机),本地IPC的机制有共享内存(shared memory)、管道(pipe)、信号(signal)等,远程IPC的机制有Socket、X25电路、WIN32命名管道(named pipe)。

    1.2 Socket API

      应用程序可以用Socket API中的C函数创建、管理本地通信端点(endpoint),即socket套接字。一个socket可以通过一个handle访问。在windows中,socket句柄和其他IO句柄不能互换。

      Socket API包含20多个系统函数,这些函数分为以下5类:

      从服务类型(stream流、datagram数据报)、连接角色(active connection establishment主动连接端,常作为client;passive connection establishment被动连接端,常作为server)、通信领域(local or remote)几个方面,对socket api进行分组,得到socket空间分布图:

    1.3 Socket API局限

      原始Socket API有以下几个局限性:容易出错、复杂、不可移植。C++ Network Program v1的2.3.1节指出socket api的数个问题。比如,sockaddr_in变量必须手动初始化,必须用htons将“主机字节顺序转换为网络字节顺序”,服务端必须按照顺序写入bind、linsten、accept,缺乏命名规范等。

    2 ACE Socket Wrapper Facade

       ACE定义了一组C++类,用来解决第一节提到的Socket API局限性,ACE Socket Wrapper Facade提供的ACE类有:

      这些ACE类的UML关系图如下:

     

      按照1.2节分类维度,将这些ACE类组合分层成如下空间图。

     2.1 ACE Socket地址簇:ACE_Addr和ACE_INET_Addr

      头文件“ace/Addr.h”和“ace/INET_Addr.h”。

      ACE_Addr和ACE_INET_Addr的构造函数实现了对通用地址的封装,避免了手动分配sockaddr_in的麻烦工作。ACE_Addr和ACE_INET_Addr的类图如下所示:

       ACE_INET_Addr内部封装了sockaddr_in,其构造函数内部会先调用reset清空sockaddr_in,然后调用set为sockaddr_in赋值。此外,ACE_Addr类还有一个static成员函数sap_any,可用作系统随机分配端口号。ACE_INET_Addr的一个例子为:

    ACE_INET_Addr      lAddr(atoi(port.c_str()),ip.c_str());

    2.2 ACE Socket机制

    2.2.1 ACE_IPC_SAP

      头文件“ace/IPC_SAP.h”

      ACE_IPC_SAP是ACE IPC wrapper facade的根节点,为其他ACE wrapper facade提供了基本的"IO句柄"操作能力。此外,ACE_IPC_SAP是一个抽象类,其构造函数声明在类的protected内,外部无法实例化。其主要方法为:

      enable和disable成对出现,用于启动或禁用某个IO选项。ACE库内给出的释义如下:

    /* Enable asynchronous I/O (ACE_SIGIO), urgent data ACE_SIGURG), non-blocking I/O (ACE_NONBLOCK), or close-on-exec (ACE_CLOEXEC), which is passed as the @a value. */
      int enable (int value) const;

     2.2.2 ACE_SOCK

      头文件“ace/SOCK.h”

      ACE_SOCK是ACE SOCK wrapper facade的根节点,从ACE_IPC_SAP派生,ACE_SOCK内部调用socket()方法创建了socket对象(ACE_SOCK内部open方法内),如下:

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

       注意:该方法在连接器ACE_SOCK_Connector的connect()方法和接收器ACE_SOCK_Acceptor的open()方法中被调用。

      除了ACE_IPC_SAP的方法外,ACE_SOCK还提供对socket的管理方法。ACE_IPC_SAP和ACE_SOCK的类关系图如下所示:

      ACE_SOCK对socket的管理方法释义如下:

      与ACE_IPC_SAP类似,ACE_SOCK的构造函数也是protected类型,仅作为抽象类供子类实例化。

      

    2.2.3 ACE_SOCK_IO和ACE_SOCK_Stream

      头文件“ace/SOCK_IO.h”和“ace/SOCK_Stream.h”

      ACE_SOCK提供了socket对象,ACE_SOCK_IO和ACE_SOCK_Stream提供socket的数据传输操作,作为一个“仅用作数据传输”的对象存在。ACE_SOCK_IO和ACE_SOCK_Stream的类关系图如下:

      ACE_SOCK_Stream提供的主要输出方法如下:

      其中,recvv_n()和sendv_n()使用结构体iovec,iovec定义如下:

      struct iovec
       {
         /// byte count to read/write
         u_long iov_len;
         /// data to be read/written
         char *iov_base;
    
         // WSABUF is a Winsock2-only type.
    #  if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0)
         operator WSABUF &(void) { return *((WSABUF *) this); }
    #  endif /* defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) */
       };

       ACE_SOCK_Stream的IO控制超时的方法如下:

    2.3 ACE Socket通信机制:ACE_SOCK_Connector和ACE_SOCK_Acceptor

      2.2节提供了ACE Socket的socket对象,本节将给出ACE Socket的通信行为连接器ACE_SOCK_Connector和接收器ACE_SOCK_Acceptor。

     2.3.1 ACE_SOCK_Connector

       头文件“ace/SOCK_Connector.h”

      ACE_SOCK_Connector类图如下:

      connect和complete方法说明如下:

      对connect超时的控制如下:

      ACE_SOCK_Connector没有自己的句柄,其connect()方法会接收一个ACE_SOCK_Stream参数,ACE_SOCK_Connector借用这个参数建立主动连接。ACE_SOCK_Connector的实例不存储状态,因此,一个ACE_SOCK_Connector的实例可以在多线程程序中重用,无需加锁

    2.3.2 ACE_SOCK_Acceptor

       头文件“ace/SOCK_Acceptor.h”

      ACE_SOCK_Acceptor的类图如下:

      open和accept方法说明:

      ACE_SOCK_Acceptor总是以正确的顺序调用socket、bind、listen函数。

    2.4 本章小结

      本章介绍了ACE Socket 的8个类,但常用的只有地址类ACE_INET_Addr、字节流类ACE_SOCK_Stream、连接器ACE_SOCK_Connector和接收器ACE_SOCK_Acceptor,其余类都是作为基类存在。第3章将针对本章涉及的类和方法,展现ACE客户端和服务端实例代码。

    3 举个栗子

      客户端和服务端共享头文件head.h:

    #include <iostream>
    
    #include "ace/INET_Addr.h"
    #include "ace/SOCK_Stream.h"
    #include "ace/SOCK_Acceptor.h"
    #include "ace/SOCK_Connector.h"
    #include "ace/Time_Value.h"
    
    using namespace std;
    
    #ifdef _DEBUG
    #pragma comment(lib,"ACEd.lib")
    #else
    #pragma comment(lib,"ACE.lib")
    #endif

      客户端代码:

    #include "head.h"
    
    int main(int argc, char **argv)
    {
        ACE_INET_Addr    addr(8890,std::string("127.0.0.1").c_str());
        ACE_SOCK_Stream s;
        ACE_SOCK_Connector    c;
        ACE_Time_Value    t(2,0);
        if (c.connect(s,addr,&t)==-1)
        {
            int errorCode = ACE_OS::last_error();
            cout<<"connector has failed"<<endl;
            return 0;
        }
        else
        {
            char* c1 = "ACE ";
            ACE_Time_Value    d(2,0);
            if (s.send(c1,4,&d) == -1)
            {
                cout<<"send has failed"<<endl;
                return 0;
            }
            char buf[BUFSIZ];
            ssize_t st = s.recv(buf,BUFSIZ,NULL);
            if (st > 0)
            {
                buf[st] = 0;
                cout<<buf<<endl;
                ::Sleep(6000);
            }
            else
            {
                cout<<"recv has failed"<<endl;
                return 0;
            }
        }
        return 1;
    }

      服务端代码:

    #include "head.h"
    
    int main(int argc, char **argv)
    {
        ACE_INET_Addr    addr(8890,std::string("127.0.0.1").c_str());
        ACE_SOCK_Stream s;
        ACE_SOCK_Acceptor    a;
        ACE_Time_Value    t(2,0);
        if (a.open(addr)==-1)
        {
            int errorCode = ACE_OS::last_error();
            cout<<"acceptor has failed"<<endl;
            return 0;
        }
        else
        {
            while (true)
            {
                if (a.accept(s) == -1)
                {
                    return 0;
                }
                else
                {
                    ACE_INET_Addr r_addr,l_addr;
                    s.get_remote_addr(r_addr);
                    char addr_str[BUFSIZ];
                    r_addr.addr_to_string(addr_str,BUFSIZ);
                    cout<<"remote address is "<<addr_str<<endl;
    
                    s.get_local_addr(l_addr);
                    l_addr.addr_to_string(addr_str,BUFSIZ);
                    cout<<"local address is "<<addr_str<<endl;
    
                    char buf[BUFSIZ];
                    ssize_t st = s.recv(buf,BUFSIZ,NULL);
                    if (st > 0)
                    {
                        buf[st]=0;
                        cout<<"receive message : "<<buf<<endl;
                    }
    
                    char* cs = "Hello";
                    if (s.send(cs,5,&t) == -1)
                    {
                        cout<<"send has failed"<<endl;
                        return 0;
                    }
                }
            }
        }
        return 1;
    }

      客户端只输出了Hello,比较简单,就不截图展示了。服务端截图如下:

    参考书:C++ Network Program v1,Mastering complexity with ACE and Patterns。

  • 相关阅读:
    JDK源码学习之 java.util.concurrent.automic包
    本地工程引入maven工程的配置方式
    JAVA配置&注解方式搭建简单的SpringMVC前后台交互系统
    Spring常用注解简析
    HTTP/HTTPS GET&POST两种方式的实现方法
    【JS语法】作用域与绑定图示
    【编程范式】函数式基础图示
    【技术思维】写好你的博客
    在Nginx服务器上用Jenkins发布Vue/React代码的步骤
    React事件绑定总结
  • 原文地址:https://www.cnblogs.com/hgwang/p/5883899.html
Copyright © 2011-2022 走看看