[ACE_Proactor网络通信示例-Part.2]

 现在我们一步步来看看实现:

先是TTcpAcceptor,该类仅重载了两个方法,如下:

#include "TCPAcceptor.h" namespace igame { int TTcpAcceptor::validate_connection (const ACE_Asynch_Accept::Result& result, const ACE_INET_Addr &remote, const ACE_INET_Addr& local) { if (m_OnClientValidate.valid()) // 这里激发TOnClientValidate事件 return m_OnClientValidate(remote.get_ip_address(), remote.get_port_number()) ? 0 : -1; else return 0; // 默认允许连接 } TTcpHandler* TTcpAcceptor::make_handler(void) { TTcpHandler* handler = 0; ACE_NEW_RETURN (handler, TTcpHandler(), 0); // 设置事件句柄 handler->setOnClientConnect(m_OnClientConnect); handler->setOnClientDisconnect(m_OnClientDisconnect); handler->setOnDataReceive(m_OnDataReceive); handler->setOnDataSendSucceeded(m_OnDataSendSucceeded); handler->setOnDataSendFailed(m_OnDataSendFailed); return handler; } } // namespace igame

 

复杂的部分在TTcpHandler,该类不仅需要接收数据(拼包),也要处理发送:

 

#include "TcpHandler.h" namespace igame { TTcpHandler::TTcpHandler() :m_CurDataMB(0) // 初始化 { } TTcpHandler::~TTcpHandler() { if (handle() != ACE_INVALID_HANDLE) { ACE_OS::closesocket(handle()); // 关闭句柄 #ifdef _DEBUG // 打印调试信息 ACE_TCHAR remoteAddrStr[128]; m_ClientAddr.addr_to_string(remoteAddrStr, sizeof(remoteAddrStr) / sizeof(ACE_TCHAR)); ACE_DEBUG((LM_INFO, ACE_TEXT("Disconnect from %s/n"), remoteAddrStr)); #endif // 客户端断开 m_OnClientDisconnect(m_ClientAddr.get_ip_address(), m_ClientAddr.get_port_number()); if (m_CurDataMB) m_CurDataMB->release(); } } int TTcpHandler::send(unsigned int seq, const char* data, unsigned short dataSize) { ACE_Message_Block* dataMB = 0; ACE_NEW_NORETURN(dataMB, ACE_Message_Block(sizeof(unsigned int) + sizeof(unsigned short) + dataSize)); short len = dataSize; dataMB->copy((const char *)&seq, sizeof(unsigned int)); // 这里没有处理seq dataMB->copy((const char *)&len, sizeof(unsigned short)); dataMB->copy((const char *)data, dataSize); int ret = m_Writer.write(*dataMB, dataMB->length()); // 发送 if (ret == -1) m_OnDataSendFailed(m_ClientAddr.get_ip_address(), m_ClientAddr.get_port_number(), seq, data, dataSize); else m_OnDataSendSucceeded(m_ClientAddr.get_ip_address(), m_ClientAddr.get_port_number(), seq, data, dataSize); return ret; } void TTcpHandler::addresses (const ACE_INET_Addr &remote_address, const ACE_INET_Addr &local_address) { m_ClientAddr = remote_address; // 取得客户端地址 } void TTcpHandler::open(ACE_HANDLE h, ACE_Message_Block& mb) { handle(h); // set handle if (m_Reader.open(*this) == -1) // 允许读 { ACE_ERROR((LM_ERROR, ACE_TEXT("failed to open read handle %i/n"), errno)); delete this; return; } if (m_Writer.open(*this) == -1) // 允许写 { ACE_ERROR((LM_ERROR, ACE_TEXT("failed to open write handle %i/n"), errno)); delete this; return; } // 激发客户端连接事件 m_OnClientConnect(m_ClientAddr.get_ip_address(), m_ClientAddr.get_port_number(), this); initCurDataMB(); m_Reader.read(*m_CurDataMB, m_CurDataMB->space()); // 读数据 } void TTcpHandler::handle_read_stream(const ACE_Asynch_Read_Stream::Result& result) { ACE_Message_Block& mb = result.message_block(); if (!result.success() || result.bytes_transferred() == 0) // no data or failed? { mb.release(); delete this; } else { if (this->m_CurDataMB->length() < TCP_PACK_HEADER_SIZE) // try to read header info { this->m_Reader.read(*m_CurDataMB, m_CurDataMB->space()); return ; } TTcpPackHeader* header = reinterpret_cast(this->m_CurDataMB->rd_ptr()); ACE_Message_Block* dataMB = this->m_CurDataMB->cont(); if (!dataMB) { ACE_NEW_NORETURN(dataMB, ACE_Message_Block(header->len)); if (dataMB) this->m_CurDataMB->cont(dataMB); else { this->m_CurDataMB->release(); ACE_DEBUG((LM_ERROR, ACE_TEXT("Failed to allocated: %i/n"), errno)); delete this; return ; } } if (dataMB->length() == header->len) { // 成功读取了数据? m_OnDataReceive(m_ClientAddr.get_ip_address(), m_ClientAddr.get_port_number(), header->seq, dataMB->rd_ptr(), header->len); m_CurDataMB->release(); initCurDataMB(); // 下一包数据 this->m_Reader.read(*m_CurDataMB, m_CurDataMB->space()); // next, try to get header return ; } this->m_Reader.read(*dataMB, dataMB->space()); // try to get data left } } void TTcpHandler::handle_write_stream(const ACE_Asynch_Write_Stream::Result& result) { if (result.success() && result.bytes_transferred() > 0) // 发送成功 { ACE_Message_Block& mb = result.message_block(); #ifdef _DEBUG ACE_TCHAR addrStr[128]; m_ClientAddr.addr_to_string(addrStr, sizeof(addrStr) / sizeof(ACE_TCHAR)); ACE_DEBUG((LM_INFO, ACE_TEXT("Send to client: %s len:%i/n"), addrStr, result.bytes_transferred())); char* ptr = mb.rd_ptr(); #endif mb.release(); } } void TTcpHandler::initCurDataMB() { ACE_NEW_NORETURN(m_CurDataMB, ACE_Message_Block(TCP_PACK_HEADER_SIZE, TCP_DATA_RECEIVE)); } } // namespace igame

 

然后是TTcpNetThread,该类的实现也相当简单:

#include #include "TCPNetThread.h" namespace igame { int TTcpNetThread::open() { return this->activate(); } int TTcpNetThread::close() { ACE_Proactor::instance()->proactor_end_event_loop(); // 终止ACE_Proactor循环 this->wait(); // 等待清理现场 return 0; } int TTcpNetThread::svc() { ACE_INET_Addr listenAddr(DEF_LISTENING_PORT); // 默认监听地址 TTcpAcceptor tcpAcceptor; // 接收器 // 设置事件 tcpAcceptor.setOnClientConnect(m_OnClientConnect); tcpAcceptor.setOnClientDisconnect(m_OnClientDisconnect); tcpAcceptor.setOnClientValidate(m_OnClientValidate); tcpAcceptor.setOnDataReceive(m_OnDataReceive); tcpAcceptor.setOnDataSendFailed(m_OnDataSendFailed); tcpAcceptor.setOnDataSendSucceeded(m_OnDataSendSucceeded); // 演出开始 if (tcpAcceptor.open(listenAddr, 0, 1, 5, 1, 0, 0) != 0) ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("%p/n"), ACE_TEXT("failed to open TcpAcceptor errno=%i/n"), errno), -1); // Proactor的事件循环开始 ACE_Proactor::instance()->proactor_run_event_loop(); ACE_DEBUG((LM_DEBUG, ACE_TEXT("Network fin/n"))); return 0; } } // namespace igame

 

最后,对以上三个类进行聚合,封装,就成了TTcp类,在此之前,先定义消息类型:

/** * @name TCP的ACE_Message_Block类型定义 @see ACE_Message_Block * @{ */ /// @brief TCP数据接收 #define TCP_DATA_RECEIVE 0x5505 /// @brief TCP客户端连接 #define TCP_CLIENT_CONNECT 0x5506 /// @brief TCP客户端断线 #define TCP_CLIENT_DISCONNECT 0x5507 /// @brief TCP数据发送 #define TCP_DATA_SEND 0x5508 /// @brief TCP数据发送成功 #define TCP_DATA_SEND_SUCCEEDED 0x5509 /// @brief TCP数据发送失败 #define TCP_DATA_SEND_FAILED 0x550A /** * @} */ /// 默认监听地址:偶的车牌号 #define DEF_LISTENING_PORT 777

现在看看TTcp的实现:

唔,太长了,下一篇吧。

 

 

 

此乃末技,

不知何用。

堆砌字数,

凑成更新。

走过路过,

不要错过。

 

 

 

你可能感兴趣的:(C++,网络,tcp,stream,header,delete,string)