【问题标题】:How do i get a function to wait for async_read_some in Boost ASIO?如何在 Boost ASIO 中获得等待 async_read_some 的函数?
【发布时间】:2017-11-21 08:10:31
【问题描述】:

情况:我正在运行一个异步 TCP 服务器,其中多个客户端同时连接是必须的。在这个特定的问题中,我有一个名为tcp_menu_id_receive() 的函数,它接收并返回客户端发送的数值。

问题:函数不等待 async_read_some() 并立即返回默认值。

int tcp_menu_id_receive()
{
    auto self(shared_from_this());

    int menuid = 0;
    socket_.async_read_some(boost::asio::buffer(data_, max_length), [this, self, &menuid](boost::system::error_code ec, std::size_t length)
    {
        if (!ec)
        {
            std::string ReceivedData(data_, data_ + length);
            menuid = std::stoi(ReceivedData);
            std::cout << "!ec menuid: " << menuid << std::endl;
        }
    });
    std::cout << "non !ec menuid: " << menuid << std::endl;

    return menuid;
}

问题:如何让`tcp_menu_id_receive'等待客户端的数据?

【问题讨论】:

    标签: c++ networking boost tcp boost-asio


    【解决方案1】:

    这实际上是async_read_some 应该做的。它将立即返回给调用者,因为它是一个异步调用。稍后,只要事件发生,就会调用 callback 函数——io_service 实际管理它。

    我相信你想使用非异步读取,也就是同步读取,这就是basic_stream_socket::read_some方法。

    【讨论】:

    • 我试过 read_some 但它会阻止其他客户端连接。
    【解决方案2】:

    简而言之,您希望在许多异步操作中同步 1 个异步操作。

    我建议使用非async_* 版本的调用。你声称read_some 不适合你:

    我尝试了 read_some 但它阻止其他客户端连接 – Chocolate Donut 1 hour ago

    我必须说我在这里有点惊讶,但你的代码不是独立的,所以我无法查看/尝试重现。

    这是一个使用deadline_timer 的“hack”,您可以将其用作“信号”。平心而论,这意味着现在您同步执行deadline_timer::wait(),并且没有真正的理由认为这与同步执行read_some 根本不同。

    但是,我的示例 是独立的,您和我可以测试它/如何测试它 有用。它可能会启发您了解其工作原理以及如何修改自己的代码。

    #include <boost/asio.hpp>
    #include <boost/optional.hpp>
    #include <iostream>
    #include <thread>
    
    namespace ba = boost::asio;
    using ba::ip::tcp;
    
    struct X : std::enable_shared_from_this<X> {
    
        X(unsigned short port) {
            socket_.connect({{}, port});
            std::cout << "connected\n";
        }
    
        ~X() {
            work_.reset();
            if (io_thread_.joinable())
                io_thread_.join();
        }
    
        int tcp_menu_id_receive()
        {
            auto self(shared_from_this());
    
            int menuid = 0;
            std::vector<char> buf(4);
    
            ba::deadline_timer sig(svc_);
            sig.expires_at(boost::posix_time::max_date_time);
    
            socket_.async_read_some(boost::asio::buffer(buf), [&, self](boost::system::error_code ec, std::size_t length)
            {
                std::cout << "Callback: " << ec.message() << "\n";
                if (!ec) {
                    std::string ReceivedData(buf.data(), length);
                    menuid = std::stoi(ReceivedData);
    
                    sig.expires_at(boost::posix_time::min_date_time);
                }
                sig.cancel(); // just abort
            });
    
            // synchronous wait
            boost::system::error_code ec;
            sig.wait(ec); // ignoring error code
    
            // optionally check result
            if (sig.expires_at() == boost::posix_time::max_date_time)
                std::cout << "Receive error\n";
    
            return menuid;
        }
    
      private:
        ba::io_service svc_;
        boost::optional<ba::io_service::work> work_{svc_};
        std::thread io_thread_ { [this] {
            std::cout << "start io_thread_\n";
            svc_.run(); 
            std::cout << "exit io_thread_\n";
        } };
        tcp::socket socket_{svc_};
    };
    
    int main() {
        auto x = std::make_shared<X>(6767);
        std::cout << "DEBUG: menuid: " << x->tcp_menu_id_receive() << "\n";
    }
    

    我使用测试服务器在我的机器上对其进行了测试:

    echo 2345 | netcat -l -p 6767
    

    输出是:

    connected
    start io_thread_
    Callback: Success
    DEBUG: menuid: 2345
    exit io_thread_
    

    【讨论】:

      猜你喜欢
      • 2021-04-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多