]>
Commit | Line | Data |
---|---|---|
92f5a8d4 TL |
1 | // |
2 | // composed_1.cpp | |
3 | // ~~~~~~~~~~~~~~ | |
4 | // | |
1e59de90 | 5 | // Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
92f5a8d4 TL |
6 | // |
7 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
8 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
9 | // | |
10 | ||
11 | #include <boost/asio/io_context.hpp> | |
12 | #include <boost/asio/ip/tcp.hpp> | |
13 | #include <boost/asio/use_future.hpp> | |
14 | #include <boost/asio/write.hpp> | |
15 | #include <cstring> | |
16 | #include <iostream> | |
17 | #include <string> | |
18 | #include <type_traits> | |
19 | #include <utility> | |
20 | ||
21 | using boost::asio::ip::tcp; | |
22 | ||
23 | //------------------------------------------------------------------------------ | |
24 | ||
25 | // This is the simplest example of a composed asynchronous operation, where we | |
26 | // simply repackage an existing operation. The asynchronous operation | |
27 | // requirements are met by delegating responsibility to the underlying | |
28 | // operation. | |
29 | ||
30 | template <typename CompletionToken> | |
31 | auto async_write_message(tcp::socket& socket, | |
32 | const char* message, CompletionToken&& token) | |
33 | // The return type of the initiating function is deduced from the combination | |
34 | // of CompletionToken type and the completion handler's signature. When the | |
35 | // completion token is a simple callback, the return type is void. However, | |
36 | // when the completion token is boost::asio::yield_context (used for stackful | |
37 | // coroutines) the return type would be std::size_t, and when the completion | |
38 | // token is boost::asio::use_future it would be std::future<std::size_t>. | |
39 | -> typename boost::asio::async_result< | |
40 | typename std::decay<CompletionToken>::type, | |
41 | void(boost::system::error_code, std::size_t)>::return_type | |
42 | { | |
43 | // When delegating to the underlying operation we must take care to perfectly | |
44 | // forward the completion token. This ensures that our operation works | |
45 | // correctly with move-only function objects as callbacks, as well as other | |
46 | // completion token types. | |
47 | return boost::asio::async_write(socket, | |
48 | boost::asio::buffer(message, std::strlen(message)), | |
49 | std::forward<CompletionToken>(token)); | |
50 | } | |
51 | ||
52 | //------------------------------------------------------------------------------ | |
53 | ||
54 | void test_callback() | |
55 | { | |
56 | boost::asio::io_context io_context; | |
57 | ||
58 | tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); | |
59 | tcp::socket socket = acceptor.accept(); | |
60 | ||
61 | // Test our asynchronous operation using a lambda as a callback. | |
62 | async_write_message(socket, "Testing callback\r\n", | |
63 | [](const boost::system::error_code& error, std::size_t n) | |
64 | { | |
65 | if (!error) | |
66 | { | |
67 | std::cout << n << " bytes transferred\n"; | |
68 | } | |
69 | else | |
70 | { | |
71 | std::cout << "Error: " << error.message() << "\n"; | |
72 | } | |
73 | }); | |
74 | ||
75 | io_context.run(); | |
76 | } | |
77 | ||
78 | //------------------------------------------------------------------------------ | |
79 | ||
80 | void test_future() | |
81 | { | |
82 | boost::asio::io_context io_context; | |
83 | ||
84 | tcp::acceptor acceptor(io_context, {tcp::v4(), 55555}); | |
85 | tcp::socket socket = acceptor.accept(); | |
86 | ||
87 | // Test our asynchronous operation using the use_future completion token. | |
88 | // This token causes the operation's initiating function to return a future, | |
89 | // which may be used to synchronously wait for the result of the operation. | |
90 | std::future<std::size_t> f = async_write_message( | |
91 | socket, "Testing future\r\n", boost::asio::use_future); | |
92 | ||
93 | io_context.run(); | |
94 | ||
95 | try | |
96 | { | |
97 | // Get the result of the operation. | |
98 | std::size_t n = f.get(); | |
99 | std::cout << n << " bytes transferred\n"; | |
100 | } | |
101 | catch (const std::exception& e) | |
102 | { | |
103 | std::cout << "Error: " << e.what() << "\n"; | |
104 | } | |
105 | } | |
106 | ||
107 | //------------------------------------------------------------------------------ | |
108 | ||
109 | int main() | |
110 | { | |
111 | test_callback(); | |
112 | test_future(); | |
113 | } |