在
win32
平台上最有效率的
IO
模型,莫过于完成端口了。
优快云
上到处都是关于完成端口的问题。在
ACE
中对
win32
平台的完成端口有着非常好的封装。
ACE
中前摄式框架的
win32
实现就是使用的完成端口。我们先来看看这个框架有哪些组成部分。
ACE_Proactor 前摄器,真怪异的名字。叫异步事件分配者多好啊。
ACE_Service_Handler 事件处理器。处理所有异步操作的结果。
ACE_Asynch_Accept 异步连接接受器。用来监听来自客户的连接请求。
ACE_Asynch_Read_Stream 异步读取器。发起异步读操作的请求。
ACE_Asynch_Write_Stream 异步写入器。发起异步写操作的请求。
嗯!东西差不多齐了。不要看到上面的东西就害怕,其实很简单,请相信我。
我们先来讲一下,运行的流程。
首先,我们会使用 Accept 的 open ()方法,,监听一个端口。
ACE_INET_Addr localhost ;
localhost . set ( 8888 ,“ 127 . 0 . 0 . 1 “);
acceptor . open ( localhost );
此时,当有客户端的连接请求到达时,前摄器会自动的调用 acceptor 的 make_handle ()方法,来创建一个事件处事器,处理这个连接的用户。
//我定义的用户事件处理器类,继承于ACE_Service_Handler
CTG_GS_User_Handler * pUser_Handler ;
//使用ACE的创建宏,分配一个空间。
ACE_NEW_NORETURN ( pUser_Handler , CTG_GS_User_Handler ( this ));
if ( pUser_Handler == NULL )
{
std :: cout << "系统为一个用户分配空间时出错,该用户不能正常登录" ;
return 0 ;
}
return pUser_Handler ;
前摄器通过调用这个方法后,得到了 pUser_Handler 的句柄,并将 socket 与这个句柄定到一起。
随后,前摄器会紧接着调用 CTG_GS_User_Handler 的 open 方法。方法的原型如下:
void ACE_Service_Handler :: open ( ACE_HANDLE new_handle ,
ACE_Message_Block & message_block
)
这是 ACE_Service_Handler 的一个虚方法,需要我们来继承,以完成我们的事件处理器的一些初始化准备。
上面我们定义的 CTG_GS_User_Handler 类,是一个很重要的组成部分,处理绝大部分的 IO 事件。他继承于 ACE_Service_Handler ,实现了以以下的三个方法。
virtual void handle_time_out ( const ACE_Time_Value & tv , const void * p );
定时器回调函数
virtual void handle_read_stream ( const ACE_Asynch_Read_Stream :: Result & result );
读操作回调函数
virtual void handle_write_stream ( const ACE_Asynch_Write_Stream :: Result & result );
写操作回调函数
比如,当我们发起一个异步的读操作时。
//reader_是一个上面提到的异步读取器
reader_ . read (* mblk_ , sizeof ( CCmdMessageHead ));
当读操作完成,或部分完成时,会回调 handle_read_stream 方法。
我们要做如下的处理。
void CTG_GS_User_Handler :: handle_read_stream ( const ACE_Asynch_Read_Stream :: Result & result )
{
//更新最后接收时间
if (! result . success ()|| result . bytes_transferred ()== 0 )
{
//如果传输不成功,或传输了0字节时返回。客户断开连接时也在这里处理。
return ;
}
else if ( result . bytes_transferred () < result . bytes_to_read ())
//如果没有接收完成,继续接收。
reader_ . read (* mblk_ , result . bytes_to_read ()- result . bytes_transferred ());
else if ( mblk_ -> length () == sizeof ( CCmdMessageHead )){
//接收头完成,扩大消息体。
CCmdMessageHead * pMsgHead ;
pMsgHead = ( CCmdMessageHead *) mblk_ -> rd_ptr ();
pMsgHead -> ulSID = this -> m_UserSID ;
//如果没有附加信息,则直接提交。
if ( pMsgHead -> ulMsgLength == 0 ){
if ( ALY_THREAD_POOL :: instance ()-> putq ( mblk_ ) == - 1 )
{
mblk_ -> release ();
return ;
}
ACE_NEW_NORETURN
( mblk_ , ACE_Message_Block ( ACE_DEFAULT_CDR_BUFSIZE ));
ACE_CDR :: mb_align ( mblk_ );
reader_ . read (* mblk_ , sizeof ( CCmdMessageHead ));
}
else
{
mblk_ -> size ( pMsgHead -> ulMsgLength + sizeof ( CCmdMessageHead ));
//将新的消息头放与消息体。
reader_ . read (* mblk_ , pMsgHead -> ulMsgLength );
}
}
else
{
//完整接收的消息放到接收线程池的接收消息列表。
if ( ALY_THREAD_POOL :: instance ()-> putq ( mblk_ ) == - 1 )
{
mblk_ -> release ();
return ;
}
ACE_NEW_NORETURN ( mblk_ , ACE_Message_Block ( ACE_DEFAULT_CDR_BUFSIZE ));
ACE_CDR :: mb_align ( mblk_ );
reader_ . read (* mblk_ , sizeof ( CCmdMessageHead ));
}
return ;
}
这样,我们就完整地接到了一个消息
ACE_Proactor 前摄器,真怪异的名字。叫异步事件分配者多好啊。
ACE_Service_Handler 事件处理器。处理所有异步操作的结果。
ACE_Asynch_Accept 异步连接接受器。用来监听来自客户的连接请求。
ACE_Asynch_Read_Stream 异步读取器。发起异步读操作的请求。
ACE_Asynch_Write_Stream 异步写入器。发起异步写操作的请求。
嗯!东西差不多齐了。不要看到上面的东西就害怕,其实很简单,请相信我。
我们先来讲一下,运行的流程。
首先,我们会使用 Accept 的 open ()方法,,监听一个端口。
ACE_INET_Addr localhost ;
localhost . set ( 8888 ,“ 127 . 0 . 0 . 1 “);
acceptor . open ( localhost );
此时,当有客户端的连接请求到达时,前摄器会自动的调用 acceptor 的 make_handle ()方法,来创建一个事件处事器,处理这个连接的用户。
//我定义的用户事件处理器类,继承于ACE_Service_Handler
CTG_GS_User_Handler * pUser_Handler ;
//使用ACE的创建宏,分配一个空间。
ACE_NEW_NORETURN ( pUser_Handler , CTG_GS_User_Handler ( this ));
if ( pUser_Handler == NULL )
{
std :: cout << "系统为一个用户分配空间时出错,该用户不能正常登录" ;
return 0 ;
}
return pUser_Handler ;
前摄器通过调用这个方法后,得到了 pUser_Handler 的句柄,并将 socket 与这个句柄定到一起。
随后,前摄器会紧接着调用 CTG_GS_User_Handler 的 open 方法。方法的原型如下:
void ACE_Service_Handler :: open ( ACE_HANDLE new_handle ,
ACE_Message_Block & message_block
)
这是 ACE_Service_Handler 的一个虚方法,需要我们来继承,以完成我们的事件处理器的一些初始化准备。
上面我们定义的 CTG_GS_User_Handler 类,是一个很重要的组成部分,处理绝大部分的 IO 事件。他继承于 ACE_Service_Handler ,实现了以以下的三个方法。
virtual void handle_time_out ( const ACE_Time_Value & tv , const void * p );
定时器回调函数
virtual void handle_read_stream ( const ACE_Asynch_Read_Stream :: Result & result );
读操作回调函数
virtual void handle_write_stream ( const ACE_Asynch_Write_Stream :: Result & result );
写操作回调函数
比如,当我们发起一个异步的读操作时。
//reader_是一个上面提到的异步读取器
reader_ . read (* mblk_ , sizeof ( CCmdMessageHead ));
当读操作完成,或部分完成时,会回调 handle_read_stream 方法。
我们要做如下的处理。
void CTG_GS_User_Handler :: handle_read_stream ( const ACE_Asynch_Read_Stream :: Result & result )
{
//更新最后接收时间
if (! result . success ()|| result . bytes_transferred ()== 0 )
{
//如果传输不成功,或传输了0字节时返回。客户断开连接时也在这里处理。
return ;
}
else if ( result . bytes_transferred () < result . bytes_to_read ())
//如果没有接收完成,继续接收。
reader_ . read (* mblk_ , result . bytes_to_read ()- result . bytes_transferred ());
else if ( mblk_ -> length () == sizeof ( CCmdMessageHead )){
//接收头完成,扩大消息体。
CCmdMessageHead * pMsgHead ;
pMsgHead = ( CCmdMessageHead *) mblk_ -> rd_ptr ();
pMsgHead -> ulSID = this -> m_UserSID ;
//如果没有附加信息,则直接提交。
if ( pMsgHead -> ulMsgLength == 0 ){
if ( ALY_THREAD_POOL :: instance ()-> putq ( mblk_ ) == - 1 )
{
mblk_ -> release ();
return ;
}
ACE_NEW_NORETURN
( mblk_ , ACE_Message_Block ( ACE_DEFAULT_CDR_BUFSIZE ));
ACE_CDR :: mb_align ( mblk_ );
reader_ . read (* mblk_ , sizeof ( CCmdMessageHead ));
}
else
{
mblk_ -> size ( pMsgHead -> ulMsgLength + sizeof ( CCmdMessageHead ));
//将新的消息头放与消息体。
reader_ . read (* mblk_ , pMsgHead -> ulMsgLength );
}
}
else
{
//完整接收的消息放到接收线程池的接收消息列表。
if ( ALY_THREAD_POOL :: instance ()-> putq ( mblk_ ) == - 1 )
{
mblk_ -> release ();
return ;
}
ACE_NEW_NORETURN ( mblk_ , ACE_Message_Block ( ACE_DEFAULT_CDR_BUFSIZE ));
ACE_CDR :: mb_align ( mblk_ );
reader_ . read (* mblk_ , sizeof ( CCmdMessageHead ));
}
return ;
}
这样,我们就完整地接到了一个消息