我正在尝试关闭asio ip :: tcp :: acceptor。以下是我正在使用的代码(松散地基于async server example)来启动和运行tcp侦听器/服务器:
启动服务:
bool TCPServer::listen()
{
try
{
if(std::atoi(_port.c_str()) <= 0)
{
LOG_ERROR("Configured port is invalid. Application will not work. Please check config file.");
return false;
}
int noOfThreads = 5;
using namespace boost::asio::ip;
tcp::endpoint endpoint(address::from_string(_host), std::atoi(_port.c_str()));
_acceptor.reset(new tcp::acceptor(_ioService, endpoint));
startAccept();
for(std::size_t i = 0; i < static_cast<unsigned>(noOfThreads); ++i)
{
_threads.push_back(std::thread(std::bind(static_cast<size_t (boost::asio::io_service::*)()>
(&boost::asio::io_service::run), &_ioService)));
}
return true;
}
catch(std::exception& e)
{
LOG_ERROR("Received exception while trying to listen at the specified address. Please verify the address"
<< " is accurate. Exception:" << e.what());
return false;
}
}
以下是上面代码中调用的startAccept()函数。它启动类“TCPConnection”的对象并将其排队到asio队列。:
void TCPServer::startAccept()
{
TCPConnection::Ptr newConn(new TCPConnection(_acceptor->get_io_service(), _processDataFn));
_acceptor->async_accept(newConn->socket(), std::bind(&TCPServer::handleAccept, this, newConn, std::placeholders::_1));
}
以下是startAccept()函数中指定的asio异步调用的handleAccept()函数:
void TCPServer::handleAccept(TCPConnection::Ptr newConn_, const boost::system::error_code& error_)
{
if (!error_)
{
newConn_->start();
}
else
{
LOG_ERROR("Encountered error while trying to accept connection. Error Code:" << error_);
}
startAccept();
}
上面的代码似乎运行正常并且听得很好。我面临的问题是关闭服务器。我使用以下代码关闭服务器。
TCPServer::~TCPServer()
{
try
{
if(!_ioService.stopped())
{
_ioService.stop();
}
if(_acceptor)
{
boost::system::error_code ec;
_acceptor->cancel(ec);
_acceptor->close(ec);
}
for(std::size_t i = 0; i < _threads.size(); ++i)
{
if(_threads[i].joinable())
{
_threads[i].join();
}
}
//_acceptor.reset(); // Hacky and causes memory leak.
}
catch(std::exception& e_)
{
LOG_ERROR("Received exception while shutting down listener. Exception:" << e_.what());
}
}
问题在于,在上面的代码中,如果注释行没有取消注释,则调用此函数的线程不会返回。如果注释行被取消注释,则会导致内存泄漏(泄漏的项目是acceptor的成员变量)。请注意,该应用程序是一个简单的GUI应用程序(我使用的是wxWidgets)。上面的listen()函数和析构函数是在各种事件中从其gui线程调用的(我不确定它是否相关。但是以防万一......)。我一直在努力奋斗几个小时。任何帮助表示赞赏。