您的位置:首页 > 理论基础 > 计算机网络

转载 用ACE开发网络通信程序

2009-03-21 17:04 295 查看
转载 用ACE开发网络通信程序
时间: 2008.12.25 13:49:00
标签:
该程序将演示如何将一个简单结构序列化后发送到网络上,如何从网络上接收到数据后反序列化回结构。

ACE的C++ WRAPPER FACADE层将网络通信分成三种角色:连接者(ACE_SOCK_Connector)、等待者(ACE_SOCK_Acceptor)和传输者(ACE_SOCK_Stream)。

建立连接
首先使用ACE_SOCK_Connector::connect连接某个服务器(使用ip地址和端口号),该服务器上使用ACE_SOCK_Acceptor::accept等待外部的连接请求。

ACE_INET_Addr类进行管理SOCKET通信使用的IP地址和端口号。

当连接建立的时候,连接者和等待者都初始化一个传输者用于通信。

下面就是连接者如何连接本机的7777端口的服务程序代码:

#include

using namespace std;

#include "ace/INET_Addr.h"

#include "ace/SOCK_Stream.h"

#include "ace/SOCK_Connector.h"

int main(void)

{

ACE_INET_Addr address("127.0.0.1:7777");

ACE_SOCK_Connector connector;

ACE_SOCK_Stream stream;

if(connector.connect(stream,address)==-1)

{

cout<

using namespace std;

#include "ace/INET_Addr.h"

#include "ace/SOCK_Stream.h"

#include "ace/SOCK_Acceptor.h"

int main(void)

{

ACE_SOCK_Acceptor acceptor;

//本地端口7777的ACE_INET_Addr对象

ACE_INET_Addr address;

address.set(7777);

//绑定本地端口,并且设置为监听状态

if(acceptor.open(address)==-1)

{

cout<

using namespace std;

#include "ace/INET_Addr.h"

#include "ace/SOCK_Stream.h"

#include "ace/SOCK_Connector.h"

#include "ace/CDR_Stream.h"

class SHMRecord

{

public:

SHMRecord():pData_(NULL){}

ACE_UINT16 type_;

ACE_UINT32 offset_;

void* pData_;

ACE_UINT32 dataLength_;

size_t size() const

{

return 2+4+4+dataLength_;

}

~SHMRecord()

{

if(pData_!=NULL)

delete[] static_cast(pData_);

}

};

int operator<<(ACE_OutputCDR & cdr,SHMRecord const& record)

{

cdr<(record.pData_),record.dataLength_);

return cdr.good_bit();

}

int operator>>(ACE_InputCDR & cdr,SHMRecord & record)

{

cdr>>record.type_;

cdr>>record.offset_;

cdr>>record.dataLength_;

record.pData_=new char[record.dataLength_]();

cdr.read_char_array(static_cast(record.pData_),record.dataLength_);

return cdr.good_bit();

}

int main(void)

{

ACE_INET_Addr address("127.0.0.1:7777");

ACE_SOCK_Connector connector;

ACE_SOCK_Stream stream;

if(connector.connect(stream,address)==-1)

{

cout<(record.pData_),"hih");

const size_t size=record.size()+ACE_CDR::MAX_ALIGNMENT;

ACE_OutputCDR payload(size);

payload
iov[0].iov_len=8;

iov[1].iov_base=payload.begin()->rd_ptr();

iov[1].iov_len=size;

stream.sendv_n(iov,2);

cout<(record.pData_)<>操作,就像上面的例子一样。

这种方式和支持标准C++流的方式是一样的。那么,为什么不直接使用标准C++流呢?因为ACE所支持的平台很多,有些编译器不支持标准C++流。并且据我个人的体验,标准C++流在内存管理上是封装的,你不可能通过公有方法获得内部关里的缓冲区的指针,除非自己定义自己的派生类,这并不容易。还有一个原因是不同编译器和不同的硬件使用了不同的字节对齐方式(大尾数法和小尾数法)。使用ACE的cdr类就可以保证各种环境下都能使用,因为它在内部使用了CORBA公共数据表示的格式。

对于基本的数值类型,各个平台也有可能有长度的差异,比如int究竟是16,32还是64。所以这里使用了ACE提供的基本数值类型,比如ACE_UINT32。

在这个示例程序里,我们实际上创建了两个ACE_OutputCDR对象,一个用来表示数据头,一个存发实际结构中的数据。数据头中前4个字节存放了一个布尔值,表示本机的字节顺序,后面四个字节表示第二个对象的实际长度。

因此,接收数据时首先接收固定长度的头对象,取得字节顺序标志后,调整字节顺序,然后获取实际长度,根据该长度接收第二个ACE_OutputCDR对象存放的实际数据。

下面的例子演示了如何接收发送来的数据。

int main(void)

{

ACE_SOCK_Acceptor acceptor;

ACE_INET_Addr address;

address.set(7777);

if(acceptor.open(address)==-1)

{

cout<

spBlock(new ACE_Message_Block(ACE_DEFAULT_CDR_BUFSIZE));

ACE_CDR::mb_align(spBlock.get());

if(stream.recv_n(spBlock->wr_ptr(),8)==8)//receive the header of CDR

{

//parse the cdr header

spBlock->wr_ptr(8);

ACE_InputCDR cdr(spBlock.get());

ACE_CDR::Boolean byte_order;

cdr>>ACE_InputCDR::to_boolean(byte_order);

cdr.reset_byte_order(byte_order);

ACE_CDR::ULong length;

cdr>>length;

//receive the data from master

spBlock->size(length+8+ACE_CDR::MAX_ALIGNMENT);

if(stream.recv_n(spBlock->wr_ptr(),length)==length)

{

spBlock->wr_ptr(length);

//必须重新创建一个CDR对象,否则解析不正确

ACE_InputCDR cdr2(spBlock.get());

ACE_CDR::Boolean byte_order;

cdr2>>ACE_InputCDR::to_boolean(byte_order);

cdr2.reset_byte_order(byte_order);

ACE_CDR::ULong length;

cdr2>>length;

auto_ptr spRecord(new SHMRecord);

cdr2>>*spRecord;

coutpData_)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: