【问题标题】:Boost asio http deadline error?Boost asio http截止日期错误?
【发布时间】:2014-03-23 18:14:47
【问题描述】:

下面的代码主要是 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));
}

【问题讨论】:

  • handle_resolve 是做什么的?另外,“截止日期可能超过我设置的时间”,你的意思是计时器回调没有及时触发,还是没有关闭套接字?
  • 不确定会发生什么,但程序卡在无休止地等待。我知道这是这个功能,但我不知道更多,因为我无法重现错误。 handle_resolve 开始发送请求。功能与http客户端示例中boost提供的功能相同。

标签: c++ boost


【解决方案1】:

您也应该在截止日期计时器上async_wait()。如果不这样做,您将不会收到通知,您只需检查(事后)时间是否已经过期。

然后,如果它完成(使用 ec 而不是 operation_aborted)那么您应该

  • cancel() 套接字上的异步操作
  • 可选择关闭套接字

附言。嗯。它/似乎/你正在做类似的事情,虽然不清楚在哪里

  • deadline_cancelled来自
  • 为什么你不接受 error_code 的完成处理程序 deadline_.async_await
  • 为什么您要手动处理时间比较,而不是相信完成处理程序的意思是什么

更新这是一个执行 HTTP 请求的完整示例。事实上,它从http://www.angio.net/pi/digits.html 下载了一百万位数的 PI。这需要一段时间。

在接收响应开始时,我将截止时间计时器设置为 800 毫秒(因此传输应该 - 正确 - 中止)。

这如宣传的那样工作。特别注意socket和timer的取消。请注意,您可以在收到每个数据块后再次调用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 不支持互联网连接)

【讨论】:

    猜你喜欢
    • 2013-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-21
    • 2014-10-10
    • 1970-01-01
    • 2021-06-18
    • 1970-01-01
    相关资源
    最近更新 更多