如何在Boost ASIO中获得等待async_read_some的函数?

时间:2017-11-21 08:10:32

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

情况:我正在运行异步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'等待客户的数据?

2 个答案:

答案 0 :(得分:1)

这实际上是async_read_some应该做的事情。它将在中间返回调用者,因为它是异步调用。之后,只要事件发生,就会调用回调函数 - io_service实际管理它。

我认为您希望使用非同步读取,即同步读取,即basic_stream_socket::read_some方法。

答案 1 :(得分:0)

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

我建议使用非async_ *版本的通话。您声称read_some并不适合您:

  

我尝试过read_some,但阻止其他客户端连接 - Chocolate Donut 1 hour ago

我必须说我在这里有点惊讶,但你的代码并不是自包含的,所以我无法复习/尝试重现。

这是&#34; hack&#34;使用deadline_timer可以用来作为&#34;信号&#34;。平心而论,这意味着现在您同步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_