c++ Boost.Beast `tcp_stream`的`async_connect`使用`use_future`等待整个持续时间

uqjltbpv  于 2023-05-02  发布在  其他
关注(0)|答案(1)|浏览(173)

我正在编写一个连接管理器类,它应该建立到服务器的连接,并使用Boost发送几个HTTP请求。Beast。它有一个connect方法,如果连接成功,应该返回true,否则返回false。我正在使用tcp_stream和它的async_connect方法与boost::asio::use_futurewait_for某种类型,并检查连接是否未能及时建立。
我的connect方法有以下代码:

// ...

const auto resolve = this->resolver.resolve(this->host, this->port);

auto connect_future = this->stream.async_connect(resolve, boost::asio::use_future);

switch (connect_future.wait_for(boost::asio::chrono::seconds{5})) {
  // Do the work
}

// ...

reolverstream关联的io_context的事件循环在事件循环线程中不断调用其run方法。它建立连接并工作,但总是等待整整5秒,直到继续。我做错了什么?
edit:在尝试创建一个最小可重复的示例时,我偶然发现了以下内容:代码在使用-DWORKING编译时干净地退出,并在没有它的情况下打印Timeout

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/use_future.hpp>
#include <boost/asio/strand.hpp>
#include <atomic>
#include <iostream>
#include <string>

// Performs an HTTP GET and prints the response
int main(int argc, char** argv)
{

    namespace net = boost::asio;
    namespace beast = boost::beast;

    net::io_context ioc;

    std::atomic_bool running = true;
    std::thread loop([&ioc, &running] {
        while (running) {
            ioc.run();
        }
    });

    net::ip::tcp::resolver resolver(net::make_strand(ioc));
    beast::tcp_stream stream(net::make_strand(ioc));

    const auto resolve = resolver.resolve("127.0.0.1", "8080");

    auto fut = stream.async_connect(resolve, net::use_future);

    switch (fut.wait_for(net::chrono::seconds(5))) {
        case std::future_status::timeout:
            std::cerr << "Timelimit" << std::endl;
            break;

        default: break;
    }

    running = false;
    loop.join();

    stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
    ioc.stop();
    return 0;
}

edit 2:更像我的实际代码的东西。然而,这不受该问题的影响。我是不是遇到了UB?

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/use_future.hpp>
#include <boost/asio/strand.hpp>
#include <atomic>
#include <iostream>
#include <string>

// Performs an HTTP GET and prints the response
int main(int argc, char** argv)
{

    namespace net = boost::asio;
    namespace beast = boost::beast;

    net::io_context ioc;

    std::atomic_bool running = true;
    std::thread loop([&ioc, &running] {
        while (running) {
            ioc.run();
        }
    });

    net::ip::tcp::resolver resolver(net::make_strand(ioc));
    beast::tcp_stream stream(net::make_strand(ioc));

    const auto resolve = resolver.resolve("127.0.0.1", "8080");

    auto fut = stream.async_connect(resolve, net::use_future);

    switch (fut.wait_for(net::chrono::seconds(5))) {
        case std::future_status::timeout:
            std::cerr << "Timelimit" << std::endl;
            break;

        default: break;
    }

    running = false;
    loop.join();

    stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
    ioc.stop();
    return 0;
}
qltillow

qltillow1#

只有当服务在不同的线程上运行时,Future才有意义。
您的线程不能保证工作:

while(running)
{
    ioc.run();
}

文档解释说,如果run()用完了工作,restart()将需要重新启动它。这意味着线程只会运行一个紧密的循环而没有任何效果(除了加热CPU)。
使用work_guardthread_pool

net::io_context ioc;
auto            work = make_work_guard(ioc);
std::thread     loop([&ioc, &running] { ioc.run(); });

或者

net::thread_pool ioc(1); // later ioc.join()

这样做的好处是,您不需要修复手写的线程来处理异常(Should the exception thrown by boost::asio::io_service::run() be caught?)。

相关问题