8e0762de49
Every I/O executor type now has an associated default completion token type. This is specified via the `default_completion_token_type` trait. This trait may be used in asynchronous operation declarations as follows: template < typename IoObject, typename CompletionToken = typename default_completion_token_type< typename IoObject::executor_type >::type > auto async_foo( IoObject& io_object, CompletionToken&& token = typename default_completion_token_type< typename IoObject::executor_type >::type{} ); If not specialised, this trait type is `void`, meaning no default completion token type is available for the given I/O executor. The `default_completion_token_type` trait is specialised for the `use_awaitable` completion token so that it may be used as shown in the following example: auto socket = use_awaitable.as_default_on(tcp::socket(my_context)); // ... co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable. In this example, type of the `socket` object is transformed from `tcp::socket` to have an I/O executor with the default completion token set to `use_awaitable`. Alternatively, the socket type may be computed directly: using tcp_socket = use_awaitable_t<>::as_default_on_t<tcp::socket>; tcp_socket socket(my_context); // ... co_await socket.async_connect(my_endpoint); // Defaults to use_awaitable.
79 lines
1.9 KiB
C++
79 lines
1.9 KiB
C++
//
|
|
// echo_server_with_default.cpp
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
|
|
#include <boost/asio/co_spawn.hpp>
|
|
#include <boost/asio/detached.hpp>
|
|
#include <boost/asio/io_context.hpp>
|
|
#include <boost/asio/ip/tcp.hpp>
|
|
#include <boost/asio/signal_set.hpp>
|
|
#include <boost/asio/write.hpp>
|
|
#include <cstdio>
|
|
|
|
using boost::asio::ip::tcp;
|
|
using boost::asio::awaitable;
|
|
using boost::asio::co_spawn;
|
|
using boost::asio::detached;
|
|
using boost::asio::use_awaitable_t;
|
|
using tcp_acceptor = use_awaitable_t<>::as_default_on_t<tcp::acceptor>;
|
|
using tcp_socket = use_awaitable_t<>::as_default_on_t<tcp::socket>;
|
|
namespace this_coro = boost::asio::this_coro;
|
|
|
|
awaitable<void> echo(tcp_socket socket)
|
|
{
|
|
try
|
|
{
|
|
char data[1024];
|
|
for (;;)
|
|
{
|
|
std::size_t n = co_await socket.async_read_some(boost::asio::buffer(data));
|
|
co_await async_write(socket, boost::asio::buffer(data, n));
|
|
}
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
std::printf("echo Exception: %s\n", e.what());
|
|
}
|
|
}
|
|
|
|
awaitable<void> listener()
|
|
{
|
|
auto executor = co_await this_coro::executor;
|
|
tcp_acceptor acceptor(executor, {tcp::v4(), 55555});
|
|
for (;;)
|
|
{
|
|
auto socket = co_await acceptor.async_accept();
|
|
co_spawn(executor,
|
|
[socket = std::move(socket)]() mutable
|
|
{
|
|
return echo(std::move(socket));
|
|
},
|
|
detached);
|
|
}
|
|
}
|
|
|
|
int main()
|
|
{
|
|
try
|
|
{
|
|
boost::asio::io_context io_context(1);
|
|
|
|
boost::asio::signal_set signals(io_context, SIGINT, SIGTERM);
|
|
signals.async_wait([&](auto, auto){ io_context.stop(); });
|
|
|
|
co_spawn(io_context, listener, detached);
|
|
|
|
io_context.run();
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
std::printf("Exception: %s\n", e.what());
|
|
}
|
|
}
|