下面的代码主要是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不支持互联网连接)

    09-07 06:47