linux下基于ACE的udp服务器问题
环境:centOS + ACE 5.7
问题:采用reactor框架,同样的代码在windows平台上很好,但在linux下失败。
代码如下:
==============================================================
启动的地方:
ACE_INET_Addr local_addr( 9005 );
CUDPRequestHandler* lpUdpHandler = NULL;
ACE_NEW_RETURN( lpUdpHandler, CUDPRequestHandler(local_addr), -1 );
if ( ACE_Reactor::instance()->register_handler( lpUdpHandler, ACE_Event_Handler::READ_MASK ) == -1 )
{
return -1;
}
CGUDPServer* lpUdpServer = NULL;
ACE_NEW_RETURN( lpUdpServer, CGUDPServer, -1 );
lpUdpServer->activate( THR_NEW_LWP|THR_JOINABLE, 4 );
==============================================================
CGUDPServer 代码
class CGUDPServer : public ACE_Task_Base
{
public:
virtual int svc(void);
virtual int handle_close(ACE_HANDLE handle, ACE_Reactor_Mask close_mask);
};
int CGUDPServer::svc(void)
{
int nResult = ACE_Reactor::instance()->run_reactor_event_loop(); // ?????????出现问题的地方?????
if ( nResult == -1 )
{
return -1;
}
return 0;
}
int CGUDPServer::handle_close(ACE_HANDLE handle, ACE_Reactor_Mask close_mask)
{
delete this;
return 0;
}
==============================================================
CUDPRequestHandler代码:
class CUDPRequestHandler : public ACE_Event_Handler
{
public:
CUDPRequestHandler( const ACE_INET_Addr& local_addr );
~CUDPRequestHandler();
virtual ACE_HANDLE get_handle(void) const;
virtual int handle_input(ACE_HANDLE fd /* = ACE_INVALID_HANDLE */);
virtual int handle_close(ACE_HANDLE handle, ACE_Reactor_Mask close_mask);
virtual int handle_timeout(const ACE_Time_Value ¤t_time, const void *act /* = 0 */);
private:
ACE_SOCK_Dgram m_gram;
};
CUDPRequestHandler::CUDPRequestHandler(const ACE_INET_Addr &local_addr):m_gram(local_addr)
{
// set timer
ACE_Time_Value initialDelay(3);
ACE_Time_Value interval(5);
ACE_Reactor::instance()->schedule_timer( this, 0, initialDelay, interval );
}
CUDPRequestHandler::~CUDPRequestHandler()
{
}
ACE_HANDLE CUDPRequestHandler::get_handle(void) const
{
return m_gram.get_handle();
}
int CUDPRequestHandler::handle_input( ACE_HANDLE fd )
{
char buf[BUFSIZ] = {0};
ACE_INET_Addr from_addr;
ssize_t nSize = m_gram.recv( buf, sizeof(buf), from_addr );
if ( nSize != -1 )
{
m_clientAddr = from_addr;
// get remote addr
ACE_TCHAR peer_name[128] = {0};
if ( from_addr.addr_to_string( peer_name, 128 ) == 0 )
{
char szAddr[255] = {0};
ACE_OS::sprintf( szAddr, ("%s udp data [%d bytes] from %s"), ACE_TEXT("%I%t"), ACE_OS::strlen(buf), peer_name );
Log( szAddr );
}
// parse
char szBuff[MAX_PATH] = {0};
sprintf( szBuff, ("[%s-%d bytes] is recv."), buf, ACE_OS::strlen(buf) );
m_gram.send( szBuff, ACE_OS::strlen(szBuff), from_addr );
}
return 0;
}
int CUDPRequestHandler::handle_close(ACE_HANDLE handle, ACE_Reactor_Mask close_mask)
{
delete this;
return 0;
}
int CUDPRequestHandler::handle_timeout(const ACE_Time_Value ¤t_time, const void *act )
{
time_t epoch = ((timespec_t)current_time).tv_sec;
ACE_DEBUG((LM_INFO, ACE_TEXT("%I%t handle_timeout: %s\n"), ACE_OS::ctime(&epoch) ));
return 0;
}
==============================================================
ok,就这么点代码,出现问题的地方就在如下:
int nResult = ACE_Reactor::instance()->run_reactor_event_loop(); // ?????????出现问题的地方?????
if ( nResult == -1 )
{
return -1;
}
当在主进程中创建线程时 :lpUdpServer->activate( THR_NEW_LWP|THR_JOINABLE, 4 );
会执行如下代码,但正常的话应该在 ACE_Reactor::instance()->run_reactor_event_loop();执行后阻塞,但在linux下,返回 -1。
这样导致客户端,发送的任何数据,int CUDPRequestHandler::handle_input( ACE_HANDLE fd ) 这个方法根本没有进来。
但以上的一切,在windows上全部正常。
非常郁闷,本人刚接触ace,希望高人指点,是因为我的使用方式上有问题,还是在linux上需要做特殊的处理?
[解决办法]
主线程里面定义handler
CUDPRequestHandler* lpUdpHandler = NULL;
在启动业务线程后,主线程即退出了
线程退出触发handle_close,进而 delete this。
可以在CUDPRequestHandler::~CUDPRequestHandler()里面增加日志打印看一下。
另外建议
int nResult = ACE_Reactor::instance()->run_reactor_event_loop();
放到主线程 进行事件循环调度。
大型网络程序应该是
udp server的svc主要应该是处理handler::handle_input收到消息后投递到本线程的数据。
你如果简单的处理,且压力不大的话你这设计也行。不过主线程别退出啊
最简单修改方式:
[1]
lpUdpServer->activate( THR_NEW_LWP|THR_JOINABLE, 4 );
后面增加
while(1){sleep(1);};
或者
[2]
把下面
int nResult = ACE_Reactor::instance()->run_reactor_event_loop();移过来确保主线程不退出。
试一下?