ACE proactor

来源:互联网 发布:linux profile 生效 编辑:程序博客网 时间:2024/04/29 06:13

1、WIN32下面用proactor可以达到几乎RAW IOCP的效率,由于封装关系,应该是差那么一点。

客户端处理类的常规写法:
//处理客户端连接消息
class ClientHandler : public ACE_Service_Handler
{
public:
/**构造函数
 *
 *
 */
ClientHandler(unsigned int client_recv_buf_size=SERVER_CLIENT_RECEIVE_BUF_SIZE)
 :_read_msg_block(client_recv_buf_size),_io_count(0)
{
}


~ClientHandler(){}

/**
 *初始化,因为可能要用到ClientHandler内存池,而这个池又不一定要用NEW
 */
void init();

/**清理函数,因为可能要用到内存池
 *
 */
void fini();


//检查是否超时的函数

void check_time_out(time_t cur_time);

public:

/**客户端连接服务器成功后调用
 *
 * /param handle 套接字句柄
 * /param &message_block 第一次读到的数据(未用)
 */


//由Acceptor来调用!!!
virtual void open (ACE_HANDLE handle,ACE_Message_Block &message_block);

/**处理网络读操作结束消息
 *
 * /param &result 读操作结果
 */
virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);


/**处理网络写操作结束消息
 *
 * /param &result 写操作结果
 */
virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);

private:

//**生成一个网络读请求
 *
 * /param void
 * /return 0-成功,-1失败
 */
int  initiate_read_stream  (void);

/**生成一个写请求
 *
 * /param mb 待发送的数据
 * /param nBytes 待发送数据大小
 * /return 0-成功,-1失败
 */
int  initiate_write_stream (ACE_Message_Block & mb, size_t nBytes );

/**
 *
 * /return 检查是否可以删除,用的是一个引用计数。每一个外出IO的时候+1,每一个IO成功后-1
 */
int check_destroy();

//异步读
ACE_Asynch_Read_Stream _rs;

//异步写
ACE_Asynch_Write_Stream _ws;

//接收缓冲区只要一个就够了,因为压根就没想过要多读,我直到现在也不是很清楚为什么要多读,多读的话要考虑很多问题
ACE_Message_Block _read_msg_block;

//套接字句柄,这个可以不要了,因为基类就有个HANDLER在里面的。
//ACE_HANDLE _handle;

//一个锁,客户端反正有东东要锁的,注意,要用ACE_Recursive_Thread_Mutex而不是用ACE_Thread_Mutex,这里面是可以重入的,而且在WIN32下是直接的EnterCriticalSection,可以达到很高的效率
ACE_Recursive_Thread_Mutex _lock;

//在外IO数量,其实就是引用计数啦,没啥的。为0的时候就把这个东东关掉啦。
long _io_count;


//检查超时用的,过段时间没东东就CLOSE他了。

time_t _last_net_io;

private:


//本来想用另外一种模型的,只用1个或者2个外出读,后来想想,反正一般内存都是足够的,就不管了。

//ACE_Message_Block _send_msg_blocks[2];

//ACE_Message_Block &_sending_msg_block;

//ACE_Message_Block &_idle_msg_block;

private:

public:
//TODO:move to prriva and use friend class!!!


//只是为了效率更高,不用STL的LIST是因为到现在我没有可用的Node_Allocator,所以效率上会有问题。
ClientHandler *_next;

ClientHandler *next(){return _next;}

void next(ClientHandler *obj){_next=obj;}

};

//这是具体实现,有些地方比较乱,懒得管了,锁的有些地方不对。懒得改了,反正在出错或者有瓶颈的时候再做也不迟。

void ClientHandler::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
{
_last_net_io=ACE_OS::time(NULL);
int byterecved=result.bytes_transferred ();
if ( (result.success ()) && (byterecved != 0))
{
 //ACE_DEBUG ((LM_DEBUG,  "Receiver completed:%d/n",byterecved));


//处理完数据
 if(handle_received_data()==true)
 {
  //ACE_DEBUG ((LM_DEBUG,  "go on reading.../n"));


//把东东推到头部,处理粘包
  _read_msg_block.crunch();
  initiate_read_stream();
 }
}


//这个地方不想用ACE_Atom_op,因为反正要有一个锁,而且一般都会用锁,不管了。假如不在意的话,应该直接用ACE_Atom_Op以达到最好的效率

{
 ACE_Guard<ACE_Recursive_Thread_Mutex> locker (_lock);
 _io_count--;
}
check_destroy ();
}

void ClientHandler::init()
{


//初始化数据,并不在构造函数里做。
_last_net_io=ACE_OS::time(NULL);
_read_msg_block.rd_ptr(_read_msg_block.base());
_read_msg_block.wr_ptr(_read_msg_block.base());
this->handle(ACE_INVALID_HANDLE);
}

bool ClientHandler::handle_received_data()
{


...........自己处理
return true;
}


//==================================================================
void ClientHandler::handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
{
//发送成功,RELEASE掉
//这个不可能有多个RELEASE,直接XX掉
//result.message_block ().release ();
MsgBlockManager::get_instance().release_msg_block(&result.message_block());

{
 ACE_Guard<ACE_Recursive_Thread_Mutex> locker (_lock);
 _io_count--;
}
check_destroy ();
}

//bool ClientHandler::destroy ()
//{
// FUNC_ENTER;
// ClientManager::get_instance().release_client_handle(this);
// FUNC_LEAVE;
// return false ;
//}


int  ClientHandler::initiate_read_stream  (void)
{
ACE_Guard<ACE_Recursive_Thread_Mutex> locker (_lock);


//考虑到粘包的呀
if (_rs.read (_read_msg_block, _read_msg_block.space()) == -1)
{
 ACE_ERROR_RETURN ((LM_ERROR,"%p/n","ACE_Asynch_Read_Stream::read"),-1);
}
_io_count++;
return 0;
}

/**生成一个写请求
*
* /param mb 待发送的数据
* /param nBytes 待发送数据大小
* /return 0-成功,-1失败
*/
int  ClientHandler::initiate_write_stream (ACE_Message_Block & mb, size_t nBytes )
{
ACE_Guard<ACE_Recursive_Thread_Mutex> locker (_lock);
if (_ws.write (mb , nBytes ) == -1)
{
 mb.release ();
 ACE_ERROR_RETURN((LM_ERROR,"%p/n","ACE_Asynch_Write_File::write"),-1);
}
_io_count++;
return 0;
}

void ClientHandler::open (ACE_HANDLE handle,ACE_Message_Block &message_block)
{
//FUNC_ENTER;
_last_net_io=ACE_OS::time(NULL);
_io_count=0;
if(_ws.open(*this,this->handle())==-1)
{
 ACE_ERROR ((LM_ERROR,"%p/n","ACE_Asynch_Write_Stream::open"));
}
else if (_rs.open (*this, this->handle()) == -1)
{
 ACE_ERROR ((LM_ERROR,"%p/n","ACE_Asynch_Read_Stream::open"));
}
else
{
 initiate_read_stream ();
}

check_destroy();
//FUNC_LEAVE;
}

void ClientHandler::fini()
{
}

void ClientHandler::check_time_out(time_t cur_time)
{
//ACE_Guard<ACE_Recursive_Thread_Mutex> locker (_lock);
//ACE_DEBUG((LM_DEBUG,"cur_time is %u,last io is %u/n",cur_time,_last_net_io));

//检测是否已经为0了
if(this->handle()==ACE_INVALID_HANDLE)
 return;
if(cur_time-_last_net_io>CLIENT_TIME_OUT_SECONDS)
{
 ACE_OS::shutdown(this->handle(),SD_BOTH);
 ACE_OS::closesocket(this->handle());
 this->handle(ACE_INVALID_HANDLE);
}
}

int ClientHandler::check_destroy()
{
{
 ACE_Guard<ACE_Recursive_Thread_Mutex> locker (_lock);
 if (_io_count> 0)
  return 1;
}
ACE_OS::shutdown(this->handle(),SD_BOTH);
ACE_OS::closesocket(this->handle());
this->handle(ACE_INVALID_HANDLE);


//这个地方给内存池吧。
ClientManager::get_instance().release_client_handle(this);
//delete this;
return 0;
}


这个也很好!ACE的好文!真是不转我觉得后悔啊!
没啥好说的,管理所有的客户端和内存池的功能。

class ClientManager : public SingleTon<ClientManager>
{
public:

ClientManager():_header(NULL){}

~ClientManager(){}

public:

void init(unsigned int default_pool_size,unsigned int default_read_buf_size);

void fini();

public:

ClientHandler *get_clienthandler();

void release_client_handle(ClientHandler *client);

void check_time_out();

size_t get_client_count();

private:

ClientHandler *_header;

std::set<ClientHandler *> _active_clients;

ACE_Recursive_Thread_Mutex _lock;
};

#include "clientmanager.h"
#include <ace/Guard_T.h>

ClientHandler *ClientManager::get_clienthandler()
{
FUNC_ENTER;
ACE_Guard<ACE_Recursive_Thread_Mutex> locker(_lock);
ClientHandler *ret=NULL;
if(_header==NULL)
{
 ACE_DEBUG((LM_DEBUG,"client > max clients!!!/n"));
}
else
{
 ret=_header;
 _header=_header->next();
 ret->init();
 _active_clients.insert(ret);
}
FUNC_LEAVE;
return ret;
}

void ClientManager::release_client_handle(ClientHandler *client)
{
//FUNC_ENTER;
ACE_Guard<ACE_Recursive_Thread_Mutex> locker(_lock);
client->fini();
client->next(_header);
_header=client;
_active_clients.erase(client);
//FUNC_LEAVE;
}

void ClientManager::init(unsigned int default_pool_size,unsigned int default_read_buf_size)
{
//FUNC_ENTER;
for(unsigned int i=0;i<default_pool_size;i++)
{
 ClientHandler *client=new ClientHandler(default_read_buf_size);
 client->next(_header);
 _header=client;
}
//FUNC_LEAVE;
}

void ClientManager::fini()
{
//FUNC_ENTER;
while(_header)
{
 ClientHandler *temp=_header->next();
 delete _header;
 _header=temp;
}
//FUNC_LEAVE;
}

void ClientManager::check_time_out()
{
time_t cur_time=ACE_OS::time(NULL);
ACE_Guard<ACE_Recursive_Thread_Mutex> locker(_lock);
for(std::set<ClientHandler *>::iterator it=_active_clients.begin();it!=_active_clients.end();it++)
{
 (*it)->check_time_out(cur_time);
}
}

size_t ClientManager::get_client_count()
{
ACE_Guard<ACE_Recursive_Thread_Mutex> locker(_lock);
return _active_clients.size();
}


//服务器的设计
按照七猫的说话,这个框架可以达到IOCP的效率,真的利害!但是我也不知道真伪!所以大家不要认为是我说的阿!我没有测试过,所以也不太清楚是否真的有那么高的效率!
没有什么可说的! 好文章!

class MyServer : public SingleTon<MyServer >
{
public:
/**主服务器初始化工作
*
* /param *listenaddr 监听地址:"192.168.0.188:80"-在192.168.0.188的80端口进行监听
"80"-在所有IP地址的80端口进行监听
* /param numOfThreads 服务器网络消息处理的线程个数
* /return 1:成功,0或者其他值:失败
*/
int init(const char *listenaddr,unsigned int numOfThreads);

/**最后清理工作,资源释放工作
 *
 */
void fini();

/**主服务器开始运行
*
* /return 1-成功,-1失败
*/
int start();

/**主服务器停止运行
*
*/
void stop();
private:
//任务管理器(线程池)
ServerTask _task;
//监听地址
ACE_INET_Addr _listen_addr;
//网络接收器
ClientAcceptor _acceptor;
//网络消息处理线程数量
unsigned int _num_of_threads;
private:

Observer _observer;

//检查是否有客户端超时
CheckClientTimeoutHandler _check_time_out_handler;
};


int MyServer::init(const char *listenaddr,unsigned int numOfThreads)
{
//ACE_WIN32_Proactor *pImpl = new ACE_WIN32_Proactor;
//static ACE_Proactor proactor(pImpl,1);
//ACE_Proactor::instance( & proactor);
_listen_addr=ACE_INET_Addr(listenaddr);
//_num_of_threads=numOfThreads;
_num_of_threads=1;
_observer.init();
_syn_cms_handler.init();
_check_time_out_handler.init();
return 1;
}

void MyServer::fini()
{
ItemManager::get_instance().purge_all_items();
_observer.fini();
_syn_cms_handler.fini();
_check_time_out_handler.fini();
}

/**主服务器开始运行
*
* /return 1-成功,-1失败
*/
int MyServer::start()
{
int Rc = _acceptor.open (_listen_addr,0,1);
if(Rc==-1)
{
 ACE_ERROR_RETURN ((LM_ERROR, "acceptor error./n"), -1);
}


//每20秒检查一次,检查是否有客户端超时
ACE_Time_Value check_client_timeout_interval(120);
Rc=ACE_Proactor::instance ()->schedule_timer (
 _check_time_out_handler,
 (void *) "timeout",
 ACE_Time_Value::zero,
 check_client_timeout_interval);
if(Rc==-1)
{
 ACE_ERROR_RETURN ((LM_ERROR, "%p/n", "check_client_timeout schedule_timer"), -1);
}

ACE_Time_Value observertime(20);
Rc=ACE_Proactor::instance ()->schedule_timer (
 _observer,
 (void *) "observer",
 ACE_Time_Value::zero,
 observertime);
if(Rc==-1)
{
 ACE_ERROR_RETURN ((LM_ERROR, "%p/n", "observer schedule_timer"), -1);
}

if (_task.activate (THR_NEW_LWP, _num_of_threads ) == -1)
{
 ACE_ERROR_RETURN ((LM_ERROR, "task start error./n", "main"), -1);
}
return 1;
}
/**主服务器停止运行
*
*/
void MyServer::stop()
{
ACE_Proactor::end_event_loop () ;
ACE_Thread_Manager * pTM = ACE_Thread_Manager::instance();

pTM->wait_task ( & _task) ;
//ACE_Proactor::instance( ( ACE_Proactor* )NULL );
}


int ACE_TMAIN(int argc,char *argv[])
{
FUNC_ENTER;
std::cout<<"size of item is "<<sizeof(Item)<<std::endl;

//设置日志
ACE_LOG_MSG->open (argv[0],ACE_Log_Msg::OSTREAM);
//std::ofstream myostream (SERVER_LOG_FILE_NAME, ios::out | ios::trunc);
//ACE_LOG_MSG->msg_ostream (&myostream);

//读入配置文件
ACE_DEBUG((LM_DEBUG,"read config file from %s/n",SERVER_CONFIG_FILE));
XMLConfig::get_instance().read_config_from_xml_file(SERVER_CONFIG_FILE);


//初始化MSGBLOCK池
ACE_DEBUG((LM_DEBUG,"starting init MsgBlockManager.../n"));
MsgBlockManager::get_instance().init(XMLConfig::get_instance().get_num_of_msg_blocks(),XMLConfig::get_instance().get_size_of_write_msg_blocks());

//初始化连接池
ACE_DEBUG((LM_DEBUG,"starting init ClientManager.../n"));
ClientManager::get_instance().init(XMLConfig::get_instance().get_num_of_clients(),XMLConfig::get_instance().get_size_of_client_read_buf());


//开始服务器

ACE_DEBUG((LM_DEBUG,"starting init MyServer.../n"));
MyServer::get_instance().init(XMLConfig::get_instance().get_listen_addr(),XMLConfig::get_instance().get_num_of_proactor_threads());

ACE_DEBUG((LM_DEBUG,"starting MyServer.../n"));
MyServer::get_instance().start();
ACE_DEBUG((LM_DEBUG,"Enter looping.../n"));

while(true)
{
 std::cout << "Input Command=>/n" << std::flush ;
 std::string inputcmd;
 std::getline(std::cin,inputcmd);
 if(!handle_console_cmd(inputcmd))
  break;
}

//char c ;
//std::cout << "Press any key to stop and exit=>/n" << std::flush ;
//std::cin.clear ();
//std::cin >> c ;
MyServer::get_instance().stop();
MsgBlockManager::get_instance().fini();
ClientManager::get_instance().fini();
return 1;
}

原创粉丝点击