提高ASIO HTTP期限错误? [英] Boost asio http deadline error?

查看:168
本文介绍了提高ASIO HTTP期限错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在code波纹管主要是用很少的更改,以支持下载期限HTTP客户端的例子。

这正常工作,但在少数情况下,例如如果互联网是不稳定的,它不工作,截止日期可以比我设置(20秒或更长时间,当我设置10)更多。这种情况很少见,我无法重现这一点,当它发生,我不指望了。

要避免张贴吨线(因为很少有人会阅读)这里是我认为错误在于地方:

  deadline_.expires_from_now(升压::了posix_time ::毫秒(截止日期));TCP ::解析器::查询查询(服务器,HTTP);
resolver_.async_resolve(查询,
提高::绑定(安培;客户:: handle_resolve,为此,
提高:: ASIO ::占位符::错误
提高:: ASIO ::占位符:迭代));deadline_.async_wait(升压::绑定(安培;客户:: check_deadline,这一点));

时的那些行的顺序是否正确?

这里是检查期限功能:

 无效check_deadline()
{
    如果(deadline_cancelled)
        返回;
    否则,如果(deadline_.expires_at()< = deadline_timer :: ::的traits_type现在())
        socket_.close();
    其他
        deadline_.async_wait(升压::绑定(安培;客户:: check_deadline,这一点));
}


在最后期限定时器

解决方案

您应该 async_wait()太。如果你不这样做,你就不会得到通知,你只要检查(事后)是否时间的中有的过期。

然后,如果它完成(与 EC 除了 operation_aborted ),那么你应该


  • 取消()插座上的异步操作

  • 选择性地关闭套接字

PS。嗯。它/似乎/你正在做类似的事情,但目前还不清楚其中


  • deadline_cancelled 源于

  • 你为什么不接受错误_ code deadline_.async_await 的完成处理和

  • 为什么要随着时间比较手动杂耍,而不是信任的完成处理说话是算数的,

更新这里有一个完整的例子做一个HTTP请求。事实上,它下载一个万位圆周率从 http://www.angio.net/pi/ digits.html 。这需要一段时间。

在接受我设定一个最后期限定时器800毫秒响应的启动(因此转移应该是 - 正确 - 中止)。

这像宣传的那样。要特别注意插座和定时器的取消。请注意,您可以接收数据的每块后, expires_from_now()再打电话。这可能是你想要的。它的取消()计时器每次有时间尚未到期,所以ppared处理<$ C $ $ P $ C> operatorion_aborted 消息。

 的#include&LT;&iostream的GT;
#包括LT&;升压/ bind.hpp&GT;
#包括LT&;升压/ asio.hpp&GT;
#包括LT&;升压/ ASIO / deadline_timer.hpp&GT;类客户端
{
    上市:
        客户端(提高:: ASIO :: io_service对象和放大器; io_service对象,
                提高:: ASIO ::知识产权:: TCP ::解析:迭代endpoint_iterator)
            :deadline_(io_service对象)
            socket_(io_service对象)
    {
        提高:: ASIO :: async_connect(socket_.lowest_layer(),endpoint_iterator,
                提高::绑定(安培;客户:: handle_connect,为此,
                    提高:: ASIO ::占位符::错误));
    }    无效handle_connect(常量的boost ::系统::错误_ code&安培;错误)
    {
        如果(!错误)
        {
            性病::法院LT&;&LT; 进入的消息:;
            静态字符常量原料[] =GET /pi/digits/pi1000000.txt HTTP / 1.1 \\ r \\ n主机:www.angio.net \\ r \\ nConnection:关闭\\ r \\ n \\ r \\ n;            static_assert(的sizeof(生)LT; = sizeof的(REQUEST_),过大);            为size_t request_length = strlen的(生);
            性病::复制(生,生+ request_length,REQUEST_);            提高:: ASIO :: async_write(socket_,
                    提高:: ASIO ::缓​​冲区(REQUEST_,request_length)
                    提高::绑定(安培;客户:: handle_write,为此,
                        提高:: ASIO ::占位符::错误
                        提高:: ASIO ::占位符:: bytes_transferred));
        }
        其他
        {
            性病::法院LT&;&LT; 握手失败:&所述;&下;返回Error.message()&所述;&下; \\ n;
        }
    }    无效deadline_expiration(常量的boost ::系统::错误_ code&安培;错误)
    {
        如果(错误==提高:: ASIO ::错误:: operation_aborted)
            返回;        性病::法院LT&;&LT; \\ nDEADLINE REACHED \\ N的;
        socket_.cancel();
    }    无效handle_write(常量的boost ::系统::错误_ code和;错误,
            为size_t / * * bytes_transferred /)
    {
        如果(!错误)
        {
            性病::法院LT&;&LT; 起点阅读循环\\ N的;            deadline_.expires_from_now(升压::了posix_time ::毫秒(800));
            //deadline_.expires_from_now(boost::posix_time::seconds(800));
            deadline_.async_wait(升压::绑定(安培;客户:: deadline_expiration,为此,提高:: ASIO ::占位符::错误));            提高:: ASIO :: async_read_until(socket_,
                    //提高:: ASIO ::缓​​冲区(reply_,sizeof的(reply_))
                    reply_,'\\ n',
                    提高::绑定(安培;客户:: handle_read,为此,
                        提高:: ASIO ::占位符::错误
                        提高:: ASIO ::占位符:: bytes_transferred));
        }
        其他
        {
            性病::法院LT&;&LT; 写失败:&LT;&LT;返回Error.message()&所述;&下; \\ n;
        }
    }    无效handle_read(常量的boost ::系统::错误_ code和;错误,为size_t / * * bytes_transferred /)
    {
        如果(!错误)
        {
            性病::法院LT&;&LT; 回复:&LT;&LT; &安培; reply_&LT;&LT; \\ n;
            提高:: ASIO :: async_read_until(socket_,
                    //提高:: ASIO ::缓​​冲区(reply_,sizeof的(reply_))
                    reply_,'\\ n',
                    提高::绑定(安培;客户:: handle_read,为此,
                        提高:: ASIO ::占位符::错误
                        提高:: ASIO ::占位符:: bytes_transferred));
        }
        其他
        {
            性病::法院LT&;&LT; 读取失败:&LT;&LT;返回Error.message()&所述;&下; \\ n;
            deadline_.cancel(); //无需后转让完成
        }
    }  私人的:
    提高:: ASIO :: deadline_timer deadline_;
    提高:: ASIO ::知识产权:: TCP ::插座socket_;
    焦炭REQUEST_ [1024];
    提高:: ASIO ::流缓冲reply_;
};诠释的main()
{
    尝试
    {
        提高:: ASIO :: io_service对象io_service对象;        提高:: ASIO ::知识产权:: TCP ::解析器解析(io_service对象);
        提高:: ASIO ::知识产权:: TCP ::解析::查询查询(www.angio.net,80);
        提高:: ASIO ::知识产权:: TCP ::解析:迭代迭代器= resolver.resolve(查询);        客户端C(io_service对象,迭代器);        io_service.run();
    }
    赶上(性病::例外急症)
    {
        的std :: CERR&LT;&LT; 例外:&LT;&LT; e.what()&所述;&下; \\ n;
    }
}

Col​​iru链接(Coliru不支持互联网连接)

The code bellow is mainly the HTTP client example with very few changes to support a download deadline.

It works as expected, but in rare cases e.g. if the internet is unstable, it doesn't work and the deadline can be more than what I set (20 or more seconds when I set 10). This happens very rarely and I am unable to reproduce this, it happens when I don't expect it.

To avoid posting a ton of lines (because few will read them) here is the place where I believe the error lies:

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));

Is the order of those lines correct?

And here is the check deadline function:

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));
}

解决方案

You should async_wait() on the deadline timer too. If you don't, you won't get notified, you just check (after the fact) whether the time had expired.

Then if it completes (with an ec other than operation_aborted) then you should

  • cancel() the async operations on the socket
  • optionally close the socket

PS. Mmm. It /seems/ that you are doing something similar, although it's unclear where

  • deadline_cancelled comes from
  • why you don't accept the error_code in the completion handler for deadline_.async_await and
  • why you are juggling with time comparisons manually, instead of trusting that the completion handler means what it says

Update Here's a full example doing a HTTP request. In fact, it downloads a million digits of PI from http://www.angio.net/pi/digits.html. This takes a while.

At the start of receiving the response I set a deadline timer for 800ms (and so the transfer should be - correctly - aborted).

This works as advertised. Pay special attention to the canceling of the socket and timer. Note that you could call expires_from_now() again after receiving each chunk of data. This is likely what you want. It will implicitly cancel() the timer each time it hadn't yet expired, so be prepared to handle the operatorion_aborted messages.

#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 doesn't support internet connectivity)

这篇关于提高ASIO HTTP期限错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆