【问题标题】:Boost.Asio async_read a string from a socketBoost.Asio async_read 从套接字中读取字符串
【发布时间】:2022-01-20 02:32:21
【问题描述】:

我正在尝试编写一个函数 async_read_string_n 以从具有 Boost.Asio 1.78(和 GCC 11.2)的套接字中异步读取正好为 n 字节的字符串。

这就是我想要使用函数async_read_string_n的方式:

void run() {
  co_spawn (io_context_, [&]() -> awaitable<void> {
    auto executor = io_context_.get_executor();
    tcp::acceptor acceptor(executor, listen_endpoint_);

    auto [ec, socket] = co_await acceptor.async_accept(as_tuple(use_awaitable));
    co_spawn(executor, [&]() -> awaitable<void> {

      auto [ec, header] = co_await async_read_string_n(socket, 6, as_tuple(use_awaitable));
      std::cerr << "received string " << header << "\n";
      co_return;
    }
    , detached);
    co_return;
  }
  , detached);
}
  

这是我按照中的建议写async_read_string_n的尝试

(我不关心内存复制。这不应该很快;它应该有一个不错的 API。)

template<class CompletionToken> auto async_read_string_n(tcp::socket& socket, int n, CompletionToken&& token) {
  async_completion<CompletionToken, void(boost::system::error_code, std::string)> init(token);
  asio::streambuf b;
  asio::streambuf::mutable_buffers_type bufs = b.prepare(n);
  auto [ec, bytes_transferred] = co_await asio::async_read(socket, bufs, asio::transfer_exactly(n), as_tuple(use_awaitable));
  b.commit(n);
  std::istream is(&b);
  std::string s;
  is >> s;
  b.consume(n);
  init.completion_handler(ec, s);
  return init.result.get();
}

编辑

(我有一个语法错误,我已修复它。)这是async_read_string_n 中的编译器错误,我一直坚持:

GCC 错误:

错误:'co_await' 不能在具有推导返回类型的函数中使用

函数async_read_string_n怎么写?

【问题讨论】:

    标签: c++ boost-asio c++20 asio c++-coroutine


    【解决方案1】:

    您不必使用streambuf。无论如何,使用&gt;&gt; 提取将无法可靠地提取字符串(空格会停止输入)。

    更大的问题是你必须选择是否要使用

    • co_await(需要另一种签名,your second link 正确显示)
    • 异步结果协议,这意味着调用者将决定使用什么机制(回调、未来、组、等待等)。

    所以要么成功:

    使用异步结果协议:

    #include <boost/asio.hpp>
    #include <boost/asio/awaitable.hpp>
    #include <boost/asio/experimental/as_tuple.hpp>
    #include <boost/asio/use_awaitable.hpp>
    #include <iostream>
    #include <iomanip>
    namespace net = boost::asio;
    using net::ip::tcp;
    using boost::system::error_code;
    
    template <typename CompletionToken>
    auto async_read_string_n(tcp::socket& socket, int n, CompletionToken&& token)
    {
        struct Op {
            net::async_completion<CompletionToken, void(error_code, std::string)>
                init;
            std::string buf;
            Op(CompletionToken token) : init(token) {}
        };
        auto op = std::make_shared<Op>(token);
    
        net::async_read(socket, net::dynamic_buffer(op->buf),
                        net::transfer_exactly(n), [op](error_code ec, size_t n) {
                            op->init.completion_handler(ec, std::move(op->buf));
                        });
        return op->init.result.get();
    }
    
    int main() {
        net::io_context ioc;
        tcp::socket s(ioc);
        s.connect({{}, 8989});
    
        async_read_string_n(s, 10, [](error_code ec, std::string s) {
            std::cout << "Read " << ec.message() << ": " << std::quoted(s)
                      << std::endl;
        });
    
        ioc.run();
    }
    

    打印

    注意此版本为您提供了您在示例run() 函数中所需的调用语义。

    使用 co_await

    类似于样本here

    boost::asio::awaitable<void> echo(tcp::socket socket)
    {
      char data[1024];
      for (;;)
      {
        auto [ec, n] = co_await socket.async_read_some(boost::asio::buffer(data),
            boost::asio::experimental::as_tuple(boost::asio::use_awaitable));
        if (!ec)
        {
          // success
        }
    
        // ...
      }
    }
    

    【讨论】:

      【解决方案2】:

      感谢@sehe 的回答,它为我提供了编写async_read_string_n 所需的信息,与co_await 一起使用:

      asio::awaitable<std::tuple<boost::system::error_code, std::string>> async_read_string_n(tcp::socket& socket, int n) {
        std::string buf;
        auto [ec, bytes_transferred] = co_await asio::async_read(socket, asio::dynamic_buffer(buf), asio::transfer_exactly(n), as_tuple(use_awaitable));
        co_return make_tuple(ec, buf);
      }
      

      像这样使用它:

      auto [ec, string6] = co_await async_read_string_n(socket, 6);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-22
        • 2015-03-07
        • 1970-01-01
        • 2011-01-03
        • 2020-11-01
        • 2010-12-12
        • 1970-01-01
        • 2012-12-17
        相关资源
        最近更新 更多