boost async_accept 不使用 boost asio use_future 选项

boost async_accept not working with the boost asio use_future option

我想在 boost::asio::ip::tcp::socket 上收听超时。为此,我使用了 std::future::wait_for 函数。下面是我的代码:

std::optional<boost::asio::ip::tcp::socket> server::listen()
{
    boost::asio::ip::tcp::socket sock(io_service);
    std::future<void> accept_status = acceptor.async_accept(
        sock, boost::asio::use_future);
    if (accept_status.wait_for(std::chrono::seconds(10)) == std::future_status::timeout)
    {
        // I hope there's no race-condition between
        // accepting a connection and calling cancel
        acceptor.cancel();
        std::cerr << "Timeout" << std::endl;
        return {};
    }
    std::cerr << "Accepted a connection" << std::endl;
    return {std::move(sock)};
}

虽然这不起作用:客户端能够连接,但我仍然超时。这意味着未来对象和异步接受函数没有通信。我错过了什么?

我正在使用 Boost 版本 1.65

对于Explorer_N,下面是一个完整的程序,它没有按我预期的方式运行:

#include <boost/asio.hpp>
#include <boost/asio/use_future.hpp>
#include <chrono>
#include <future>
#include <iostream>
#include <thread>

using namespace std;

void server_listen() {
    boost::asio::io_service io_service;
    boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 31132);
    boost::asio::ip::tcp::acceptor acceptor(io_service, endpoint);
    boost::asio::ip::tcp::socket socket(io_service);
    std::future<void> accept_status = acceptor.async_accept(
            socket, boost::asio::use_future);
    while(true) {
        if(accept_status.wait_for(std::chrono::seconds(10)) == std::future_status::timeout) {
            acceptor.cancel();
            std::cerr << "Timeout\n";
        } else {
            break;
        }
    }
    // if I replace the lines starting from the async_accept call
    // by just the following, everything works as expected
    // acceptor.accept(socket);
    std::cout << "Accepted a connection\n";
    while(true) {
    }
}

void client_connect() {
    boost::asio::io_service io_service;
    boost::asio::ip::tcp::resolver resolver(io_service);
    boost::asio::ip::tcp::socket socket(io_service);
    boost::asio::ip::tcp::endpoint endpoint(*resolver.resolve({"127.0.0.1", std::to_string(31132)}));
    socket.connect(endpoint);
    std::cout << "Connected to server\n";
    while(true) {
    }
}

int main() {
    std::thread server(server_listen);
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::thread client(client_connect);
    while(true) {
    }
}

g++ -std=c++17 <program>.cpp -lpthread -lboost_system -o <program>编译。

我得到的输出是:

Connected to server
Timeout
Timeout
Timeout
Timeout
Timeout
Timeout
Timeout
Timeout
Timeout
Timeout
Timeout
Timeout
Timeout
...

回答您的要求:

"future object and the asynchronous accept function aren't communicating" -- 不可能。

"the client is able to connect, but I still get a timeout.", -- 您的客户端连接到侦听器是一个事件,执行 completion-handler(设置 promise)是另一个事件。

因此连接可能在第 9 秒接受,回调将安排在第 11 秒 运行(例如)。

请记住,我们正在处理异步操作,因此我认为对未来事件进行绝对预测是不正确的。

除了

// I hope there's no race-condition between
        // accepting a connection and calling cancel
        acceptor.cancel();
        std::cerr << "Timeout" << std::endl;
        return {};

acceptor.cancel(); 只是收集待处理的等待者,并用 ec 设置为 operation_aborted 来完成它们,如果处理程序已经出到完成事件队列,则 cancel() 是一个no-op

根据 OP 最近的编辑扩展我的答案:

using namespace std;

void server_listen() {
    boost::asio::io_service io_service;
    boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 31132);
    boost::asio::ip::tcp::acceptor acceptor(io_service, endpoint);
    boost::asio::ip::tcp::socket socket(io_service);
    auto work = make_work_guard(io_service);
    using type= std::decay_t<decltype(work)>;
    std::thread io([&](){io_service.run();});
    std::future<void> accept_status = acceptor.async_accept(
            socket, boost::asio::use_future);
    if(accept_status.wait_for(std::chrono::seconds(10)) == std::future_status::timeout) {
        acceptor.cancel();
        std::cerr << "Timeout\n";
        work.~type();
        //break;
    } else {
        std::cout<<"future is ready\n";
        work.~type();
       // break;
    }

    io.join();
    // if I replace the lines starting from the async_accept call
    // by just the following, everything works as expected
    // acceptor.accept(socket);
    std::cout << "Accepted a connection\n";

}

void client_connect() {
    boost::asio::io_service io_service;
    boost::asio::ip::tcp::resolver resolver(io_service);
    boost::asio::ip::tcp::socket socket(io_service);
    boost::asio::ip::tcp::endpoint endpoint(*resolver.resolve({"127.0.0.1", std::to_string(31132)}));
    socket.connect(endpoint);
    std::cout << "Connected to server\n";

}
enter code here
int main() {
    std::thread server(server_listen);
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::thread client(client_connect);
    server.join(); client.join();
}

在你的程序中有很多事情需要注意(避免不必要的 spin-loop,不要忘记加入或分离 std::thread 并确保你调用 io_service::run当你使用 async* 版本时)

Start
Connected to server
future is ready
Accepted a connection
0
Finish