• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // composed_1.cpp
3 // ~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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>
async_write_message(tcp::socket & socket,const char * message,CompletionToken && token)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   //
40   // In C++14 we can omit the return type as it is automatically deduced from
41   // the return type of our underlying asynchronous operation
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 
test_callback()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 
test_future()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 
main()109 int main()
110 {
111   test_callback();
112   test_future();
113 }
114