下面的代码主要是HTTP客户端示例,只需很少更改即可支持下载期限。
它可以按预期工作,但在极少数情况下,例如如果互联网不稳定,它将无法正常工作,并且截止日期可能会超过我设置的时间(设置10时为20秒或更多)。这种情况很少发生,我无法重现,当我不期望时会发生。
为了避免发布大量的行(因为很少有人阅读它们),这是我认为错误所在的位置:
deadline_.expires_from_now(boost::posix_time::milliseconds(deadline));
tcp::resolver::query query(server, "http");
resolver_.async_resolve(query,
boost::bind(&client::handle_resolve, this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
deadline_.async_wait(boost::bind(&client::check_deadline, this));
这些行的顺序正确吗?
这是检查截止日期功能:
void check_deadline()
{
if(deadline_cancelled)
return;
else if (deadline_.expires_at() <= deadline_timer::traits_type::now())
socket_.close();
else
deadline_.async_wait(boost::bind(&client::check_deadline, this));
}
最佳答案
您也应该在截止时间计时器上使用async_wait()
。如果您不这样做,则不会收到通知,您只需(在事后)检查时间是否已过期。
然后,如果完成(使用ec
以外的operation_aborted
),则应该
cancel()
对套接字的异步操作PS。嗯/似乎/您正在做类似的事情,尽管不清楚在哪里
deadline_cancelled
来自error_code
和deadline_.async_await
更新这是执行HTTP请求的完整示例。实际上,它从http://www.angio.net/pi/digits.html下载一百万位数的PI。这需要一段时间。
在开始接收响应时,我将最后期限计时器设置为800毫秒(因此,传输应该-正确-中止)。
这工作如广告。请特别注意取消套接字和计时器。请注意,您可以在接收到每个数据块之后再次调用
expires_from_now()
。这可能是您想要的。每次计时器尚未到期时,它都会隐式 cancel()
,因此请准备处理operatorion_aborted
消息。#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/asio/deadline_timer.hpp>
class client
{
public:
client(boost::asio::io_service& io_service,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
: deadline_(io_service),
socket_(io_service)
{
boost::asio::async_connect(socket_.lowest_layer(), endpoint_iterator,
boost::bind(&client::handle_connect, this,
boost::asio::placeholders::error));
}
void handle_connect(const boost::system::error_code& error)
{
if (!error)
{
std::cout << "Enter message: ";
static char const raw[] = "GET /pi/digits/pi1000000.txt HTTP/1.1\r\nHost: www.angio.net\r\nConnection: close\r\n\r\n";
static_assert(sizeof(raw)<=sizeof(request_), "too large");
size_t request_length = strlen(raw);
std::copy(raw, raw+request_length, request_);
boost::asio::async_write(socket_,
boost::asio::buffer(request_, request_length),
boost::bind(&client::handle_write, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "Handshake failed: " << error.message() << "\n";
}
}
void deadline_expiration(const boost::system::error_code& error)
{
if (error == boost::asio::error::operation_aborted)
return;
std::cout << "\nDEADLINE REACHED\n";
socket_.cancel();
}
void handle_write(const boost::system::error_code& error,
size_t /*bytes_transferred*/)
{
if (!error)
{
std::cout << "starting read loop\n";
deadline_.expires_from_now(boost::posix_time::millisec(800));
//deadline_.expires_from_now(boost::posix_time::seconds(800));
deadline_.async_wait(boost::bind(&client::deadline_expiration, this, boost::asio::placeholders::error));
boost::asio::async_read_until(socket_,
//boost::asio::buffer(reply_, sizeof(reply_)),
reply_, '\n',
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "Write failed: " << error.message() << "\n";
}
}
void handle_read(const boost::system::error_code& error, size_t /*bytes_transferred*/)
{
if (!error)
{
std::cout << "Reply: " << &reply_ << "\n";
boost::asio::async_read_until(socket_,
//boost::asio::buffer(reply_, sizeof(reply_)),
reply_, '\n',
boost::bind(&client::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
std::cout << "Read failed: " << error.message() << "\n";
deadline_.cancel(); // no need for after transfer completed
}
}
private:
boost::asio::deadline_timer deadline_;
boost::asio::ip::tcp::socket socket_;
char request_[1024];
boost::asio::streambuf reply_;
};
int main()
{
try
{
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query("www.angio.net", "80");
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
client c(io_service, iterator);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
}
Coliru link(Coliru不支持互联网连接)