sockets - boost async_accept无法与boost asio use_future选项一起使用

标签 sockets c++11 boost-asio future

我想听一个带有超时的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
...

最佳答案

回答您的要求:

“将来的对象和异步接受函数无法通信”-不可能。

“客户端可以连接,但是我仍然会超时。”,-您的客户端连接到监听器是一个事件,执行完成处理程序(设置Promise)是另一个事件。

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

记住,我们正在处理异步操作,因此对 future 事件进行绝对预测并不是我想说的。

分开的形式

// 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()是一个空操作

根据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();
}

程序中有很多事情要注意(避免不必要的自旋循环,不要忘记加入或分离std::thread并确保在使用io_service::run版本时调用async*)
Start
Connected to server
future is ready
Accepted a connection
0
Finish

关于sockets - boost async_accept无法与boost asio use_future选项一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56615760/

相关文章:

python - 如何捕获多个异常?

javascript - AJAX 还是 socket.io?

PHP 套接字 - 只能从本地主机连接(端口转发问题?)

c++ - asio::strand<asio::io_context::executor_type> 与 io_context::strand

c++ - Boost 客户端无法从服务器接收消息

c++ - 在 Windows 上的环回接口(interface)上使用 tcp/ip 的延迟方面可以预期什么?

c++ - 使用 boost socket ,我只需要一个io_service吗?

c++ - 为什么非静态数据成员初始化程序会破坏统一初始化语法?

c++ - 作用于可 move 但不可复制对象序列的变异 STL 算法的行为

c++ - 为什么在使用大括号初始值设定项列表时首选 std::initializer_list 构造函数?