beast: http socket timeout / keepalive

Hi, I want to establish a http socket connection for longer times. That’s why I set the

req.keep_alive(true)

flag of the …

http::request<http::empty_body> req;

…Object. Sadly I still experience timeouts (end of stream error 1) after about 1:30 min. So what is the intended way to keep the connection alive? Is there a ping/pong mechanism I have to use?

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 15

Most upvoted comments

Expressed as a “traditional” chain of continuations:

struct active_request
{
    asio::ip::tcp::socket& sock;
    asio::ip::tcp::endpoint ep;
    beast::flat_buffer rxbuf;
    beast::http::request<beast::http::string_body> req;
    beast::http::response<beast::http::string_body> resp;

    asio::any_io_executor exec_ { sock.get_executor() };
    bool reconnect = true;

    virtual void on_done(error_code ec);

    void start()
    {
        asio::dispatch(asio::bind_executor(exec_, std::bind(&active_request::step1, this)));
    }

    void step1()
    {
        beast::http::async_write(sock, 
            req, 
            asio::bind_executor(exec_, 
                [this](auto...args){
                    this->handle_write(args...);
                }));
    }

    void handle_write(error_code ec, std::size_t size)
    {
        if (!ec)
            beast::http::async_read(
                sock, 
                rxbuf, 
                resp, 
                asio::bind_executor(
                    exec_, 
                    [this](auto...args) {
                        this->handle_read(args...);
                    }));
        else
            handle_read(ec, size);

    }

    void 
    handle_read(error_code ec, std::size_t)
    {
        if (!ec)
            on_done(ec);
        else if(reconnect)
        {
            reconnect = false;
            sock.close();
            rxbuf.clear();
            sock.async_connect(
                ep,
                asio::bind_executor(
                    exec_, 
                    [this](auto...args) {
                        this->handle_connect(args...);
                    }));
        }
        else
            handle_connect(ec);
    }

    void
    handle_connect(error_code ec)
    {
        if (ec)
            this->on_done(ec);
        else
            step1();
    }
};

Something like this:

template<class CompletionHandler>
auto async_use_existing(
    asio::ip::tcp::socket& sock, 
    asio::ip::tcp::endpoint ep,
    beast::flat_buffer& rxbuf,
    beast::http::request<beast::http::string_body> const& req,
    beast::http::response<beast::http::string_body>& resp, 
    CompletionHandler&& handler)
{
    return asio::async_compose<CompletionHandler, void(error_code)>(
        [&sock, ep, &rxbuf, &req, &resp, reconnect = true, coro = asio::coroutine()]
        (auto&& self, error_code ec = {}, std::size_t = 0) 
        mutable
        {
            BOOST_ASIO_CORO_REENTER(coro)
            for(;;)
            {
                BOOST_ASIO_CORO_YIELD
                    beast::http::async_write(sock, req, std::move(self));
                if (!ec)
                    BOOST_ASIO_CORO_YIELD
                        beast::http::async_read(sock, rxbuf, resp, std::move(self));
                if (!ec) {
                    self.complete(ec);
                    return;
                }

                if (reconnect) {
                    reconnect = false;
                    sock.close();
                    rxbuf.clear();
                    BOOST_ASIO_CORO_YIELD
                        sock.async_connect(ep, std::move(self));
                    if(!ec) continue;
                }

                self.complete(ec);
                return;
            }

        }, handler, sock);
}


void test(asio::ip::tcp::socket& sock, 
    asio::ip::tcp::endpoint ep,
    beast::flat_buffer& rxbuf,
    beast::http::request<beast::http::string_body> const& req)
{
    auto resp = std::make_shared<beast::http::response<beast::http::string_body>>();
    async_use_existing(sock, ep, rxbuf, req, *resp, [resp](error_code){
        // handle response;
    });
}