Boost.Asio async_read 来自套接字的字符串
Boost.Asio async_read a string from a socket
我正在尝试编写一个函数 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
,遵循
中的建议
- https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.automatic_deduction_of_initiating_function_return_type
- https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/overview/core/cpp20_coroutines.html#boost_asio.overview.core.cpp20_coroutines.error_handling
(我不关心内存复制。这不应该很快;它应该有一个很好的 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 错误:
error: 'co_await' cannot be used in a function with a deduced return type
如何编写函数async_read_string_n
?
您不必使用 streambuf
。无论如何,使用 >>
提取不会可靠地提取字符串(空格会停止输入)。
更大的问题是你必须选择是否要使用
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();
}
版画
NOTE This version affords you the calling semantics that you desire in your sample run()
function.
或 使用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
}
// ...
}
}
谢谢@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);
我写了一个 post 关于这个:https://github.com/xc-jp/blog-posts/blob/master/Asio-Coroutines.md
我正在尝试编写一个函数 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
,遵循
- https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.automatic_deduction_of_initiating_function_return_type
- https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/overview/core/cpp20_coroutines.html#boost_asio.overview.core.cpp20_coroutines.error_handling
(我不关心内存复制。这不应该很快;它应该有一个很好的 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 错误:
error: 'co_await' cannot be used in a function with a deduced return type
如何编写函数async_read_string_n
?
您不必使用 streambuf
。无论如何,使用 >>
提取不会可靠地提取字符串(空格会停止输入)。
更大的问题是你必须选择是否要使用
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();
}
版画
NOTE This version affords you the calling semantics that you desire in your sample
run()
function.
或 使用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
}
// ...
}
}
谢谢@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);
我写了一个 post 关于这个:https://github.com/xc-jp/blog-posts/blob/master/Asio-Coroutines.md