Я реализую что-то похожее на 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_;
};
Для этого нет чистого способа. Единственный способ гарантировать, что обработчики, готовые к запуску, такие как Connection::callback()
, не будут вызываться:
io_service
событий io_service
.io_service
, поскольку деструктор io_service
уничтожение всех выдающихся обработчиков. В примере кода рассмотрите возможность возврата в Connection::callback()
если сокет больше не открыт:
void callback(const boost::system::error_code& error)
{
if (!socket_.is_open()) return;
// ...
}
Также обратите внимание, что аргумента error_code
недостаточно, чтобы определить, произошло ли время ожидания. Возможно, что Connection::callback()
boost::system::errc::success
очередь для вызова с error_code
boost::system::errc::success
при boost::system::errc::success
socket::close()
. Следовательно, нет никаких операций для отмены.
callback()
вызывается перед разрушениемConnection
, тогда рассмотрите возможность отделения времени жизниConnection
от обработчика обратного вызова черезboost::weak_ptr
. Этот ответ демонстрирует базовуюweak_ptr
слабого указателя, и этот ответ явно передаетweak_ptr
обработчику. В любом из решений будет вызываться обработчик, ноcallback()
будет вызываться только в том случае, еслиConnection
активно.