我正在实现看起来像HTTP服务器的东西,设计是:对于已经建立的连接,我想为多个请求重用它,所以当请求是我的时候,我开始另一个带有async_read
的阅读任务完成了,并开始deadline_timer
。如果在60秒内没有输入,则会触发定时器并破坏连接。令我烦恼的是,在调用连接的析构函数之前,我们将调用我们设置为async_read
的回调。
所以,我的问题是,有没有办法取消挂起的读取任务,即在没有调用回调函数的情况下破坏连接?
如果上面的一般描述不清楚,详细工作流程如下(代码附在底部):
cleanup()
在请求完成时被调用; cleanup()
; HandleTimeout()
,并调用stop()
; stop()
中,执行清理工作,之后,连接实例将被破坏。但是,在第4步之后,将调用callback()
函数,该函数在AsyncRead()
中注册,那么,有没有办法取消callback()
的调用?
代码:
class Connection : public boost::enable_shared_from_this<Connection>,
private boost::noncopyable {
public:
typedef Connection this_type;
void cleanup() {
timer_.expires_from_now(boost::posix_time::seconds(kDefaultTimeout));
timer_.async_wait(boost::bind(&this_type::HandleTimeout,
shared_from_this(),
boost::asio::placeholders::error));
AsyncRead();
}
void AsyncRead() {
boost::asio::async_read(*socket_, in_, boost::asio::transfer_at_least(1),
boost::bind(&this_type::callback,
shared_from_this(),
boost::asio::placeholders::error));
}
void callback(const boost::system::error_code& e) {
// ...
}
void HandleTimeout(const boost::system::error_code& e) {
if(e == boost::asio::error::operation_aborted)
LDEBUG << "The timeout timer is cancelled.";
else if(e)
LERROR << "Error occurred with the timer, message: " << e.message();
else if(timer_.expires_at()
<= boost::asio::deadline_timer::traits_type::now()) {
LDEBUG << "Connection timed out, close it.";
stop();
}
}
virtual void stop() {
connected_ = false;
socket_->close();
connection_manager_.stop(shared_from_this());
}
private:
// ...
boost::asio::deadline_timer timer_;
};
答案 0 :(得分:1)
没有干净的方法来实现这一目标。保证不会调用即用型处理程序(如Connection::callback()
)的唯一方法是:
io_service
事件循环。io_service
,因为io_service
的析构函数会导致所有未处理的处理程序被销毁。在示例代码中,如果套接字不再打开,请考虑在Connection::callback()
中返回:
void callback(const boost::system::error_code& error)
{
if (!socket_.is_open()) return;
// ...
}
另请注意,error_code
参数不足以推断是否已发生超时。调用socket::close()
时,Connection::callback()
可能会在error_code
boost::system::errc::success
的情况下排队等待调用。因此,没有取消的操作。