设为首页 收藏本站
查看: 908|回复: 0

[经验分享] ACE网络编程笔记(2):IPC SAP、ACE_SOCKET和TCP/IP通信实例

[复制链接]

尚未签到

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

  
DSC0000.gif
  根据底层使用的不同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()调用)。
  下面的例子演示接收器和连接器是怎样用于建立连接的。该连接随后将用于使用流数据传输类来传输数据。



#include "ace/SOCK_Acceptor.h"
#include "ace/SOCK_Stream.h"
#include "ace/Log_Msg.h"
#define SIZE_DATA 18
#define SIZE_BUF 1024
#define NO_ITERATIONS 5
class Server
{
public:
///初始化
Server(int port): server_addr_(port),peer_acceptor_(server_addr_)
{
data_buf_= new char[SIZE_BUF];
}
///建立监听
int accept_connections()
{
if (peer_acceptor_.get_local_addr (server_addr_) == -1)
{
ACE_ERROR_RETURN ((LM_ERROR,"%p\n","Error in get_local_addr"),1);
ACE_DEBUG ((LM_DEBUG,"Starting server at port %d\n",
server_addr_.get_port_number ()));
}
while(1)
{
ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
if (peer_acceptor_.accept (new_stream_, &client_addr_, &timeout)== -1)
{
ACE_ERROR ((LM_ERROR, "%p\n", "accept"));
continue;
}
else
{
ACE_DEBUG((LM_DEBUG,
"Connection established with remote %s:%d\n",
client_addr_.get_host_name(),client_addr_.get_port_number()));
handle_read();
}
}
}
///读取流内容
int handle_read()
{
for(int i=0;i<NO_ITERATIONS;i++)
{
int byte_count=0;
if( (byte_count=new_stream_.recv_n (data_buf_, SIZE_DATA, 0))==-1)
{
ACE_ERROR ((LM_ERROR, "%p\n", "Error in recv"));
}
else
{
data_buf_[byte_count]=0;
ACE_DEBUG((LM_DEBUG,"Server received %s \n",data_buf_));
}
}
if (new_stream_.close () == -1)
{
ACE_ERROR ((LM_ERROR, "%p\n", "close"));
}
return 0;
}
private:
char *data_buf_;
ACE_INET_Addr server_addr_;//地址

ACE_INET_Addr client_addr_;
ACE_SOCK_Acceptor peer_acceptor_;
ACE_SOCK_Stream new_stream_;//流

};
int ACE_TMAIN (int, ACE_TCHAR *[])
{
Server server(8002);
server.accept_connections();
return 0;
};
  上面的例子创建了一个被动服务器,侦听到来的客户连接。在连接建立后,服务器接收来自客户的数据,然后关闭连接。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资源并终止连接。
  下面的例子演示怎样与前面例子中演示的接受器协同使用连接器。



#include "ace/SOCK_Connector.h"
#include "ace/INET_Addr.h"
#include "ace/Log_Msg.h"
#define SIZE_BUF 128
#define NO_ITERATIONS 5
class Client
{
public:
Client(char *hostname, int port):remote_addr_(port,hostname)
{
data_buf_="Hello from Client";
}
int connect_to_server()
{
ACE_DEBUG ((LM_DEBUG, "(%P|%t) Starting connect to %s:%d\n",
remote_addr_.get_host_name(),remote_addr_.get_port_number()));
if (connector_.connect (client_stream_, remote_addr_) == -1)
{
ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","connection failed"),-1);
}
else
{
ACE_DEBUG ((LM_DEBUG,"(%P|%t) connected to %s\n",
remote_addr_.get_host_name ()));
}
return 0;
}
int send_to_server()
{
for(int i=0;i<NO_ITERATIONS; i++)
{
if (client_stream_.send_n (data_buf_,
ACE_OS::strlen(data_buf_)+1, 0) == -1)
{
ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","send_n"),0);
break;
}
}
close();
}
int close()
{
if (client_stream_.close () == -1)
{
ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","close"),-1);
}
else
{
return 0;
}
}
private:
ACE_SOCK_Stream client_stream_;
ACE_INET_Addr remote_addr_;
ACE_SOCK_Connector connector_;
char *data_buf_;
};
int ACE_TMAIN (int, ACE_TCHAR *[])
{
Client client("127.0.0.1", 8002);   
client.connect_to_server();
client.send_to_server();
return 0;
};
  上面的例子演示的客户主动连接到服务器。在建立连接后,客户将单个字符串发送若干次到服务器,并关闭连接。
  客户由单个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()方法来完成的。
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-115592-1-1.html 上篇帖子: POJ 2455 Secret Milking Machine (Dinic + 二分 或 二分+SAP) 下篇帖子: SAP Roll out项目和本地项目哪一个好做?(三)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表