socket、TLI、STREAM管道和FIFO为访问局部和全局IPC机制提供广泛的接口。但是,有许多问题与这些不统一的接口有关联。比如类型安全的缺乏和多维度的复杂性会导致成问题的和易错的编程。ACE的IPC SAP类属提供了统一的层次类属,对那些麻烦而易错的接口进行封装。在保持高性能的同时,IPC SAP被设计用于改善通信软件的正确性、易学性、可移植性和可复用性。

IPC SAP类属


  根据底层使用的不同IPC接口,IPC SAP类被划分为四种主要的类属,图2-1描述了这一划分。ACE_IPC_SAP类提供的一些函数是所有IPC接口公有的。有四个不同的类由此类派生而出,每个类各自代表ACE包含的一种IPC SAP包装类属。这些类封装适用于特定IPC接口的功能。例如,ACE_SOCK类包含的功能适用于BSD socket编程接口,而ACE_TLI包装TLI编程接口。

  在这四个类的每一个类下面都有一整层次的包装类,它们完整地包装底层接口,并提供高度可复用、模块化、安全和易用的包装类。下面重点介绍一下最常用的socket类属。

socket类属(ACE_SOCK)


  该类属中的类都位于ACE_SOCK之下;它提供使用BSD socket编程接口的Internet域和UNIX域协议族的接口。这个类属中的类被进一步划分为:
  Dgram类和Stream类:Dgram类基于UDP数据报协议,提供不可靠的无连接消息传递功能。另一方面,Stream类基于TCP协议,提供面向连接的消息传递。
  Acceptor、Connector类和Stream类:Acceptor和Connector类分别用于被动和主动地建立连接。Acceptor类封装BSD accept()调用,而Connector封装BSD connect()调用。Stream类用于在连接建立之后提供双向的数据流,并包含有发送和接收方法。

 下表详细描述了该类属中的类以及它们的职责:

类名

职责

ACE_SOCK_Acceptor

用于被动的连接建立,基于BSD accept()和listen()调用。

ACE_SOCK_Connector

用于主动的连接建立,基于BSD connect()调用。

ACE_SOCK_Dgram

用于提供基于UDP(用户数据报协议)的无连接消息传递服务。封装了sendto()和receivefrom()等调用,并提供了简单的send()和recv()接口。

ACE_SOCK_IO

用于提供面向连接的消息传递服务。封装了send()、recv()和write()等调用。该类是ACE_SOCK_Stream和ACE_SOCK_CODgram类的基类。

ACE_SOCK_Stream

用于提供基于TCP(传输控制协议)的面向连接的消息传递服务。派生自ACE_SOCK_IO,并提供了更多的包装方法。

ACE_SOCK_CODgram

用于提供有连接数据报(connected datagram)抽象。派生自ACE_SOCK_IO;它包含的open()方法使用bind()来绑定到指定的本地地址,并使用UDP连接到远地地址。

ACE_SOCK_Dgram_Mcast

用于提供基于数据报的多点传送(multicast)抽象。包括预订多点传送组,以及发送和接收消息的方法

ACE_SOCK_Dgram_Bcast

用于提供基于数据报的广播(broadcast)抽象。包括在子网中向所有接口广播数据报消息的方法

  在下面的部分,我们将要演示怎样将IPC_SAP包装类直接用于处理进程间通信。

使用ACE的流


  ACE中的流包装提供面向连接的通信。流数据传输包装类包括ACE_SOCK_Stream和ACE_LSOCK_Stream,它们分别包装TCP/IP和UNIX域socket协议数据传输功能。连接建立类包括针对TCP/IP的ACE_SOCK_Connector和ACE_SOCK_Acceptor,以及针对UNIX域socket的ACE_LSOCK_Connector和ACE_LSOCK_Acceptor。

  Acceptor类用于被动地接受连接(使用BSD accept()调用),而Connector类用于主动地建立连接(使用BSD connect()调用)。

  下面的例子演示接收器和连接器是怎样用于建立连接的。该连接随后将用于使用流数据传输类来传输数据。

  1. #include "ace/SOCK_Acceptor.h"
  2. #include "ace/SOCK_Stream.h"
  3. #include "ace/Log_Msg.h"
  4. #define SIZE_DATA 18
  5. #define SIZE_BUF 1024
  6. #define NO_ITERATIONS 5
  7.  
  8. class Server
  9. {
  10. public:
  11. ///初始化
  12. Server(int port): server_addr_(port),peer_acceptor_(server_addr_)
  13. {
  14. data_buf_= new char[SIZE_BUF];
  15. }
  16.  
  17. ///建立监听
  18. int accept_connections()
  19. {
  20. if (peer_acceptor_.get_local_addr (server_addr_) == -1)
  21. {
  22. ACE_ERROR_RETURN ((LM_ERROR,"%p\n","Error in get_local_addr"),1);
  23. ACE_DEBUG ((LM_DEBUG,"Starting server at port %d\n",
  24. server_addr_.get_port_number ()));
  25. }
  26. while(1)
  27. {
  28. ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
  29. if (peer_acceptor_.accept (new_stream_, &client_addr_, &timeout)== -1)
  30. {
  31. ACE_ERROR ((LM_ERROR, "%p\n", "accept"));
  32. continue;
  33. }
  34. else
  35. {
  36. ACE_DEBUG((LM_DEBUG,
  37. "Connection established with remote %s:%d\n",
  38. client_addr_.get_host_name(),client_addr_.get_port_number()));
  39. handle_read();
  40. }
  41. }
  42. }
  43.  
  44. ///读取流内容
  45. int handle_read()
  46. {
  47. for(int i=0;i<NO_ITERATIONS;i++)
  48. {
  49. int byte_count=0;
  50. if( (byte_count=new_stream_.recv_n (data_buf_, SIZE_DATA, 0))==-1)
  51. {
  52. ACE_ERROR ((LM_ERROR, "%p\n", "Error in recv"));
  53. }
  54. else
  55. {
  56. data_buf_[byte_count]=0;
  57. ACE_DEBUG((LM_DEBUG,"Server received %s \n",data_buf_));
  58. }
  59. }
  60. if (new_stream_.close () == -1)
  61. {
  62. ACE_ERROR ((LM_ERROR, "%p\n", "close"));
  63. }
  64. return 0;
  65. }
  66. private:
  67. char *data_buf_;
  68.  
  69. ACE_INET_Addr server_addr_;//地址
  70.  
  71. ACE_INET_Addr client_addr_;
  72.  
  73. ACE_SOCK_Acceptor peer_acceptor_;
  74.  
  75. ACE_SOCK_Stream new_stream_;//流
  76.  
  77. };
  78.  
  79. int ACE_TMAIN (int, ACE_TCHAR *[])
  80. {
  81.  
  82. Server server(8002);
  83. server.accept_connections();
  84.  
  85. return 0;
  86. };

  上面的例子创建了一个被动服务器,侦听到来的客户连接。在连接建立后,服务器接收来自客户的数据,然后关闭连接。Server类表示该服务器。

  Server类包含的accept_connections()方法使用接受器(也就是ACE_SOCK_Acceptor)来将连接接受“进”ACE_SOCK_Stream new_stream_。该操作是这样来完成的:调用接受器上的accept(),并将流作为参数传入其中;我们想要接受器将连接接受进这个流。一旦连接已建立进流中,流的包装方法send()和recv()就可以用来在新建立的链路上发送和接收数据。还有一个空的ACE_INET_Addr client_addr_也被传入接受器的accept()方法,并在其中被设定为发起连接的远地机器的地址。

  在连接建立后,服务器调用handle_read()方法,它开始从客户那里读取一个预先知道的单词,然后将流关闭。对于要处理多个客户的服务器来说,这也许并不是很实际的情况。在现实世界的情况中可能发生的是,连接在单独的线程或进程中被处理。在后续章节中将反复演示怎样完成这样的多线程和多进程类型的处理。

  连接关闭通过调用流上的close()方法来完成,该方法会释放所有的socket资源并终止连接。

  下面的例子演示怎样与前面例子中演示的接受器协同使用连接器。

  1. #include "ace/SOCK_Connector.h"
  2. #include "ace/INET_Addr.h"
  3. #include "ace/Log_Msg.h"
  4. #define SIZE_BUF 128
  5. #define NO_ITERATIONS 5
  6.  
  7. class Client
  8. {
  9. public:
  10. Client(char *hostname, int port):remote_addr_(port,hostname)
  11. {
  12. data_buf_="Hello from Client";
  13. }
  14.  
  15. int connect_to_server()
  16. {
  17. ACE_DEBUG ((LM_DEBUG, "(%P|%t) Starting connect to %s:%d\n",
  18. remote_addr_.get_host_name(),remote_addr_.get_port_number()));
  19.  
  20. if (connector_.connect (client_stream_, remote_addr_) == -1)
  21. {
  22. ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","connection failed"),-1);
  23. }
  24. else
  25. {
  26. ACE_DEBUG ((LM_DEBUG,"(%P|%t) connected to %s\n",
  27. remote_addr_.get_host_name ()));
  28. }
  29.  
  30. return 0;
  31.  
  32. }
  33.  
  34. int send_to_server()
  35. {
  36. for(int i=0;i<NO_ITERATIONS; i++)
  37. {
  38. if (client_stream_.send_n (data_buf_,
  39. ACE_OS::strlen(data_buf_)+1, 0) == -1)
  40. {
  41. ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","send_n"),0);
  42. break;
  43. }
  44. }
  45. close();
  46. }
  47.  
  48. int close()
  49. {
  50. if (client_stream_.close () == -1)
  51. {
  52. ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","close"),-1);
  53. }
  54. else
  55. {
  56. return 0;
  57. }
  58. }
  59. private:
  60. ACE_SOCK_Stream client_stream_;
  61.  
  62. ACE_INET_Addr remote_addr_;
  63.  
  64. ACE_SOCK_Connector connector_;
  65.  
  66. char *data_buf_;
  67.  
  68. };
  69.  
  70. int ACE_TMAIN (int, ACE_TCHAR *[])
  71. {
  72.  
  73. Client client("127.0.0.1", 8002);
  74. client.connect_to_server();
  75. client.send_to_server();
  76.  
  77. return 0;
  78. };

  上面的例子演示的客户主动连接到服务器。在建立连接后,客户将单个字符串发送若干次到服务器,并关闭连接。

  客户由单个Client类表示。Client含有connect_to_server()和send_to_server()方法。

  Connect_to_server()方法使用类型为ACE_SOCK_Connector的连接器(connector_)来主动地建立连接。连接的设置通过调用连接器connector_上的connect()方法来完成:传入的参数为我们想要连接的机器的地址remote_addr_,以及用于在其中建立连接的空ACE_SOCK_Stream client_stream_。远地机器在例子的运行时参数中指定。一旦connect()方法成功返回,通过使用ACE_SOCK_Stream封装类中的send()和recv()方法族,流就可以用于在新建立的链路上发送和接收数据了。

  在此例中,一旦连接建立好,send_to_server()方法就会被调用,以将一个字符串发送NO_ITERATIONS次到服务器。如前面所提到的,这是通过使用流包装类的send()方法来完成的。

ACE网络编程:IPC SAP、ACE_SOCKET和TCP/IP通信实例的更多相关文章

  1. 网络编程的基本概念,TCP/IP协议简介

    8.1.1 网络基础知识 计算机网络形式多样,内容繁杂.网络上的计算机要互相通信,必须遵循一定的协议.目前使用最广泛的网络协议是Internet上所使用的TCP/IP协议. 网络编程的目的就是指直接或 ...

  2. Java 网络编程(五) 使用TCP/IP的套接字(Socket)进行通信

    链接地址:http://www.cnblogs.com/mengdd/archive/2013/03/10/2952616.html 使用TCP/IP的套接字(Socket)进行通信 套接字Socke ...

  3. Linux 网络编程详解五(TCP/IP协议粘包解决方案二)

    ssize_t recv(int s, void *buf, size_t len, int flags); --与read相比,只能用于网络套接字文件描述符 --当flags参数的值设置为MSG_P ...

  4. 《Unix网络编程》卷一(简介TCP/IP、基础套接字编程)

    通常说函数返回某个错误值,实际上是函数返回值为-1,而全局变量errno被置为指定的常值(即称函数返回这个错误值). exit终止进程,Unix在一个进程终止时总是关闭该进程所有打开的描述符. TCP ...

  5. 网络编程 套接字socket TCP UDP

    网络编程与套接字 网络编程 网络编程是什么: ​ 网络通常指的是计算机中的互联网,是由多台计算机通过网线或其他媒介相互链接组成的 ​ 编写基于网络的应用程序的过程序称之为网络编程. 网络编程最主要的工 ...

  6. golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期

    欢迎访问我的个人网站获取更佳阅读排版 golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期 | yoko blog (https://pengrl.com/p/47401/) 本篇文章部 ...

  7. linux高性能服务器编程 (四) --TCP/IP通信案例

    第四章 TCP/IP通信案例 HTTP代理服务器的大致工作原理        在HTTP通信链上,客户端和服务器之间通常存在某些中转代理服务器.它们提供对目标资源的中转访问.一个HTTP请求可能被多个 ...

  8. TCP/IP通信网络基础

    TCP/IP是互联网相关的各类协议族的总称. TCP/IP的分层管理 分层的优点:如果只有一个协议在互联网上统筹,某个地方修改就要把所有的部分整体换掉,采用分层则只需要改变相应的层.把各个接口部分规划 ...

  9. 第4章 TCP/IP通信案例:访问Internet上的Web服务器

    第4章 TCP/IP通信案例:访问Internet上的Web服务器 4.2 部署代理服务器 书中为了演示访问Internet上的Web服务器的全过程,使用了squid代理服务器程序模拟了一个代理服务器 ...

随机推荐

  1. D3力布图绘制--基本方法

    本文主要结合案例记录使用D3.js绘制力布图的基本方法 样例显示 基本配置 this.force = d3.layout .force() .size([this.width, this.height ...

  2. 一段完整的创建表格的SQL代码

    一段完整的创建表格的SQL代码 使用SQL语句创建一张表,不仅可以可以快速熟悉SQL语句,还可以从这看出一个人对该技能点的熟悉程度. 这里先说明几点: PRIMARY KEY:主键,一张表中只允许有一 ...

  3. linux 查找被删除但是未被释放空间的文件 并释放资源

    使用du -sh  和df -h 查看/data目录,发现结果相差一半,后来了解到: 使用rm命令删除文件时,只有当该文件不存在任何link才会被删除 当有进程访问这个文件时,这个文件的实际占用空间就 ...

  4. JVM的监控工具之jmap

    参考博客:https://www.jianshu.com/p/a4ad53179df3 jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为heapdump或dump文件 ...

  5. 【题解】NOIP2016提高组 复赛

    [题解]NOIP2016提高组 复赛 传送门: 玩具谜题 \(\text{[P1563]}\) 天天爱跑步 \(\text{[P1600]}\) 换教室 \(\text{[P1850]}\) 组合数问 ...

  6. Windows Form父子两个窗体之间的传值测试

    1:先看测试的效果图: 2:全部的代码 using System; using System.Windows.Forms; namespace WindowsForms { public partia ...

  7. WPF数据模板(7)

    数据模板常用在3种类型的控件, 下图形式: 1.Grid这种列表表格中修改Cell的数据格式, CellTemplate可以修改单元格的展示数据的方式. 2.针对列表类型的控件, 例如树形控件,下拉列 ...

  8. MySQL基础(四)(子查询与链接)

    1.子查询简介 其中,所谓的“外层查询”并不是指“查找”,指的是所有SQL语句的统称:结构化查询语言(Structured Query Language),简称SQL. : 2.由比较运算符引发的子查 ...

  9. 什么是LNMP架构

    LNMP是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写.L指Linux,N指Nginx,M一般指MySQL,也可以指MariaDB,P一般指PHP,也可以指Perl或Python ...

  10. 安装配置ZooKeeper及基本用法

    要想学习分布式应用,ZooKeeper是一个绕不过去的基础系统.它为大型分布式计算提供开源的分布式配置服务.同步服务和命名注册. 今天先介绍系统的安装和基本使用,后续会推一些基本的Java使用代码. ...