| src/examples/cpp03/timeouts/blocking_token_tcp_client.cpp | src/examples/cpp11/timeouts/blocking_token_tcp_client.cpp | 
| ⋮ | ⋮ | 
| 1  | // | 1  | // | 
| 2  | //·blocking_token_tcp_client.cpp | 2  | //·blocking_token_tcp_client.cpp | 
| 3  | //·~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 3  | //·~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 
| 4  | // | 4  | // | 
| 5  | //·Copyright·(c)·2003-2023·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) | 5  | //·Copyright·(c)·2003-2023·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) | 
| 6  | // | 6  | // | 
| 7  | //·Distributed·under·the·Boost·Software·License,·Version·1.0.·(See·accompanying | 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) | 8  | //·file·LICENSE_1_0.txt·or·copy·at·http://www.boost.org/LICENSE_1_0.txt) | 
| 9  | // | 9  | // | 
| 10  |  | 10  |  | 
| 11  | #include·"asio/connect.hpp" | 11  | #include·"asio/connect.hpp" | 
| 12  | #include·"asio/io_context.hpp" | 12  | #include·"asio/io_context.hpp" | 
| 13  | #include·"asio/ip/tcp.hpp" | 13  | #include·"asio/ip/tcp.hpp" | 
| 14  | #include·"asio/read_until.hpp" | 14  | #include·"asio/read_until.hpp" | 
| 15  | #include·"asio/streambuf.hpp" | 15  | #include·"asio/streambuf.hpp" | 
| 16  | #include·"asio/system_error.hpp" | 16  | #include·"asio/system_error.hpp" | 
| 17  | #include·"asio/write.hpp" | 17  | #include·"asio/write.hpp" | 
| 18  | #include·<cstdlib> | 18  | #include·<cstdlib> | 
| 19  | #include·<iostream> | 19  | #include·<iostream> | 
| 20  | #include·<memory> | 20  | #include·<memory> | 
| 21  | #include·<string> | 21  | #include·<string> | 
| 22  |  | 22  |  | 
| 23  | using·asio::ip::tcp; | 23  | using·asio::ip::tcp; | 
| 24  |  | 24  |  | 
|   | 25  | //·NOTE:·This·example·uses·the·new·form·of·the·asio::async_result·trait. | 
|   | 26  | //·For·an·example·that·works·with·the·Networking·TS·style·of·completion·tokens, | 
|   | 27  | //·please·see·an·older·version·of·asio. | 
|   | 28  |  | 
| 25  | //·We·will·use·our·sockets·only·with·an·io_context. | 29  | //·We·will·use·our·sockets·only·with·an·io_context. | 
| 26  | typedef·asio::basic_stream_socket<tcp, | 30  | using·tcp_socket·=·asio::basic_stream_socket< | 
| 27  | ····asio::io_context::executor_type>·tcp_socket; | 31  | ····tcp,·asio::io_context::executor_type>; | 
| 28  |  | 32  |  | 
| 29  | //---------------------------------------------------------------------- | 33  | //---------------------------------------------------------------------- | 
| 30  |  | 34  |  | 
| 31  | //·A·custom·completion·token·that·makes·asynchronous·operations·behave·as | 35  | //·A·custom·completion·token·that·makes·asynchronous·operations·behave·as | 
| 32  | //·though·they·are·blocking·calls·with·a·timeout. | 36  | //·though·they·are·blocking·calls·with·a·timeout. | 
| 33  | struct·close_after | 37  | struct·close_after | 
| 34  | { | 38  | { | 
| 35  | ··close_after(asio::chrono::steady_clock::duration·t,·tcp_socket&·s) | 39  | ··close_after(std::chrono::steady_clock::duration·t,·tcp_socket&·s) | 
| 36  | ····:·timeout_(t),·socket_(s) | 40  | ····:·timeout_(t),·socket_(s) | 
| 37  | ··{ | 41  | ··{ | 
| 38  | ··} | 42  | ··} | 
| 39  |  | 43  |  | 
| 40  | ··//·The·maximum·time·to·wait·for·an·asynchronous·operation·to·complete. | 44  | ··//·The·maximum·time·to·wait·for·an·asynchronous·operation·to·complete. | 
| 41  | ··asio::chrono::steady_clock::duration·timeout_; | 45  | ··std::chrono::steady_clock::duration·timeout_; | 
| 42  |  | 46  |  | 
| 43  | ··//·The·socket·to·be·closed·if·the·operation·does·not·complete·in·time. | 47  | ··//·The·socket·to·be·closed·if·the·operation·does·not·complete·in·time. | 
| 44  | ··tcp_socket&·socket_; | 48  | ··tcp_socket&·socket_; | 
| 45  | }; | 49  | }; | 
| 46  |  | 50  |  | 
| 47  | namespace·asio·{ | 51  | namespace·asio·{ | 
| 48  |  | 52  |  | 
| 49  | //·The·async_result·template·is·specialised·to·allow·the·close_after·token·to | 53  | //·The·async_result·template·is·specialised·to·allow·the·close_after·token·to | 
| 50  | //·be·used·with·asynchronous·operations·that·have·a·completion·signature·of | 54  | //·be·used·with·asynchronous·operations·that·have·a·completion·signature·of | 
| 51  | //·void(error_code,·T).·Generalising·this·for·all·completion·signature·forms·is | 55  | //·void(error_code,·T).·Generalising·this·for·all·completion·signature·forms·is | 
| 52  | //·left·as·an·exercise·for·the·reader. | 56  | //·left·as·an·exercise·for·the·reader. | 
| 53  | template·<typename·T> | 57  | template·<typename·T> | 
| 54  | class·async_result<close_after,·void(asio::error_code,·T)> | 58  | class·async_result<close_after,·void(std::error_code,·T)> | 
| 55  | { | 59  | { | 
| 56  | public: | 60  | public: | 
| 57  | ··//·An·asynchronous·operation's·initiating·function·automatically·creates·an | 61  | ··//·The·initiate()·function·is·used·to·launch·the·asynchronous·operation·by | 
| 58  | ··//·completion_handler_type·object·from·the·token.·This·function·object·is | 62  | ··//·calling·the·operation's·initiation·function·object.·For·the·close_after | 
| 59  | ··//·then·called·on·completion·of·the·asynchronous·operation. | 63  | ··//·completion·token,·we·use·this·function·to·run·the·io_context·until·the | 
| 60  | ··class·completion_handler_type | 64  | ··//·operation·is·complete. | 
|   | 65  | ··template·<typename·Init,·typename...·Args> | 
|   | 66  | ··static·T·initiate(Init·init,·close_after·token,·Args&&...·args) | 
| 61  | ··{ | 67  | ··{ | 
| 62  | ··public: |  | 
| 63  | ····completion_handler_type(const·close_after&·token) |  | 
| 64  | ······:·token_(token) |  | 
| 65  | ····{ |  | 
| 66  | ····} |  | 
| 67  |  |  | 
| 68  | ····void·operator()(asio::error_code·ec,·T·t) |  | 
| 69  | ····{ |  | 
| 70  | ······*ec_·=·ec; |  | 
| 71  | ······*t_·=·t; |  | 
| 72  | ····} |  | 
| 73  |  |  | 
| 74  | ··private: |  | 
| 75  | ····friend·class·async_result; |  | 
| 76  | ····close_after·token_; |  | 
| 77  | ····asio::error_code*·ec_; |  | 
| 78  | ····T*·t_; |  | 
| 79  | ··}; |  | 
| 80  |  |  | 
| 81  | ··//·The·async_result·constructor·associates·the·completion·handler·object·with |  | 
| 82  | ··//·the·result·of·the·initiating·function. |  | 
| 83  | ··explicit·async_result(completion_handler_type&·h) |  | 
| 84  | ····:·timeout_(h.token_.timeout_), |  | 
| 85  | ······socket_(h.token_.socket_) |  | 
| 86  | ··{ |  | 
| 87  | ····h.ec_·=·&ec_; |  | 
| 88  | ····h.t_·=·&t_; |  | 
| 89  | ··} |  | 
| 90  |  |  | 
| 91  | ··//·The·return_type·typedef·determines·the·result·type·of·the·asynchronous |  | 
| 92  | ··//·operation's·initiating·function. |  | 
| 93  | ··typedef·T·return_type; |  | 
| 94  |  |  | 
| 95  | ··//·The·get()·function·is·used·to·obtain·the·result·of·the·asynchronous |  | 
| 96  | ··//·operation's·initiating·function.·For·the·close_after·completion·token,·we |  | 
| 97  | ··//·use·this·function·to·run·the·io_context·until·the·operation·is·complete. |  | 
| 98  | ··return_type·get() |  | 
| 99  | ··{ |  | 
| 100  | ····asio::io_context&·io_context·=·asio::query( | 68  | ····asio::io_context&·io_context·=·asio::query( | 
| 101  | ········socket_.get_executor(),·asio::execution::context); | 69  | ········token.socket_.get_executor(),·asio::execution::context); | 
| 102  |  | 70  |  | 
|   | 71  | ····//·Call·the·operation's·initiation·function·object·to·start·the·operation. | 
|   | 72  | ····//·A·lambda·is·supplied·as·the·completion·handler,·to·be·called·when·the | 
|   | 73  | ····//·operation·completes. | 
|   | 74  | ····std::error_code·error; | 
|   | 75  | ····T·result; | 
|   | 76  | ····init([&](std::error_code·e,·T·t) | 
|   | 77  | ········{ | 
|   | 78  | ··········error·=·e; | 
|   | 79  | ··········result·=·t; | 
|   | 80  | ········},·std::forward<Args>(args)...); | 
|   | 81  |  | 
| 103  | ····//·Restart·the·io_context,·as·it·may·have·been·left·in·the·"stopped"·state | 82  | ····//·Restart·the·io_context,·as·it·may·have·been·left·in·the·"stopped"·state | 
| 104  | ····//·by·a·previous·operation. | 83  | ····//·by·a·previous·operation. | 
| 105  | ····io_context.restart(); | 84  | ····io_context.restart(); | 
| 106  |  | 85  |  | 
| 107  | ····//·Block·until·the·asynchronous·operation·has·completed,·or·timed·out.·If | 86  | ····//·Block·until·the·asynchronous·operation·has·completed,·or·timed·out.·If | 
| 108  | ····//·the·pending·asynchronous·operation·is·a·composed·operation,·the·deadline | 87  | ····//·the·pending·asynchronous·operation·is·a·composed·operation,·the·deadline | 
| 109  | ····//·applies·to·the·entire·operation,·rather·than·individual·operations·on | 88  | ····//·applies·to·the·entire·operation,·rather·than·individual·operations·on | 
| 110  | ····//·the·socket. | 89  | ····//·the·socket. | 
| 111  | ····io_context.run_for(timeout_); | 90  | ····io_context.run_for(token.timeout_); | 
| 112  |  | 91  |  | 
| 113  | ····//·If·the·asynchronous·operation·completed·successfully·then·the·io_context | 92  | ····//·If·the·asynchronous·operation·completed·successfully·then·the·io_context | 
| 114  | ····//·would·have·been·stopped·due·to·running·out·of·work.·If·it·was·not | 93  | ····//·would·have·been·stopped·due·to·running·out·of·work.·If·it·was·not | 
| 115  | ····//·stopped,·then·the·io_context::run_for·call·must·have·timed·out·and·the | 94  | ····//·stopped,·then·the·io_context::run_for·call·must·have·timed·out·and·the | 
| 116  | ····//·operation·is·still·incomplete. | 95  | ····//·operation·is·still·incomplete. | 
| 117  | ····if·(!io_context.stopped()) | 96  | ····if·(!io_context.stopped()) | 
| 118  | ····{ | 97  | ····{ | 
| 119  | ······//·Close·the·socket·to·cancel·the·outstanding·asynchronous·operation. | 98  | ······//·Close·the·socket·to·cancel·the·outstanding·asynchronous·operation. | 
| 120  | ······socket_.close(); | 99  | ······token.socket_.close(); | 
| 121  |  | 100  |  | 
| 122  | ······//·Run·the·io_context·again·until·the·operation·completes. | 101  | ······//·Run·the·io_context·again·until·the·operation·completes. | 
| 123  | ······io_context.run(); | 102  | ······io_context.run(); | 
| 124  | ····} | 103  | ····} | 
| 125  |  | 104  |  | 
| 126  | ····//·If·the·operation·failed,·throw·an·exception.·Otherwise·return·the·result. | 105  | ····//·If·the·operation·failed,·throw·an·exception.·Otherwise·return·the·result. | 
| 127  | ····return·ec_·?·throw·asio::system_error(ec_)·:·t_; | 106  | ····return·error·?·throw·std::system_error(error)·:·result; | 
| 128  | ··} | 107  | ··} | 
| 129  |  |  | 
| 130  | private: |  | 
| 131  | ··asio::chrono::steady_clock::duration·timeout_; |  | 
| 132  | ··tcp_socket&·socket_; |  | 
| 133  | ··asio::error_code·ec_; |  | 
| 134  | ··T·t_; |  | 
| 135  | }; | 108  | }; | 
| 136  |  | 109  |  | 
| 137  | }·//·namespace·asio | 110  | }·//·namespace·asio | 
| 138  |  | 111  |  | 
| 139  | //---------------------------------------------------------------------- | 112  | //---------------------------------------------------------------------- | 
| 140  |  | 113  |  | 
| 141  | int·main(int·argc,·char*·argv[]) | 114  | int·main(int·argc,·char*·argv[]) | 
| 142  | { | 115  | { | 
| 143  | ··try | 116  | ··try | 
| 144  | ··{ | 117  | ··{ | 
| 145  | ····if·(argc·!=·4) | 118  | ····if·(argc·!=·4) | 
| 146  | ····{ | 119  | ····{ | 
| 147  | ······std::cerr·<<·"Usage:·blocking_tcp_client·<host>·<port>·<message>\n"; | 120  | ······std::cerr·<<·"Usage:·blocking_tcp_client·<host>·<port>·<message>\n"; | 
| 148  | ······return·1; | 121  | ······return·1; | 
| 149  | ····} | 122  | ····} | 
| 150  |  | 123  |  | 
| 151  | ····asio::io_context·io_context; | 124  | ····asio::io_context·io_context; | 
| 152  |  | 125  |  | 
| 153  | ····//·Resolve·the·host·name·and·service·to·a·list·of·endpoints. | 126  | ····//·Resolve·the·host·name·and·service·to·a·list·of·endpoints. | 
| 154  | ····tcp::resolver::results_type·endpoints·= | 127  | ····auto·endpoints·=·tcp::resolver(io_context).resolve(argv[1],·argv[2]); | 
| 155  | ······tcp::resolver(io_context).resolve(argv[1],·argv[2]); |  | 
| 156  |  | 128  |  | 
| 157  | ····tcp_socket·socket(io_context); | 129  | ····tcp_socket·socket(io_context); | 
| 158  |  | 130  |  | 
| 159  | ····//·Run·an·asynchronous·connect·operation·with·a·timeout. | 131  | ····//·Run·an·asynchronous·connect·operation·with·a·timeout. | 
| 160  | ····asio::async_connect(socket,·endpoints, | 132  | ····asio::async_connect(socket,·endpoints, | 
| 161  | ········close_after(asio::chrono::seconds(10),·socket)); | 133  | ········close_after(std::chrono::seconds(10),·socket)); | 
| 162  |  | 134  |  | 
| 163  | ····asio::chrono::steady_clock::time_point·time_sent·= | 135  | ····auto·time_sent·=·std::chrono::steady_clock::now(); | 
| 164  | ······asio::chrono::steady_clock::now(); |  | 
| 165  |  | 136  |  | 
| 166  | ····//·Run·an·asynchronous·write·operation·with·a·timeout. | 137  | ····//·Run·an·asynchronous·write·operation·with·a·timeout. | 
| 167  | ····std::string·msg·=·argv[3]·+·std::string("\n"); | 138  | ····std::string·msg·=·argv[3]·+·std::string("\n"); | 
| 168  | ····asio::async_write(socket,·asio::buffer(msg), | 139  | ····asio::async_write(socket,·asio::buffer(msg), | 
| 169  | ········close_after(asio::chrono::seconds(10),·socket)); | 140  | ········close_after(std::chrono::seconds(10),·socket)); | 
| 170  |  | 141  |  | 
| 171  | ····for·(std::string·input_buffer;;) | 142  | ····for·(std::string·input_buffer;;) | 
| 172  | ····{ | 143  | ····{ | 
| 173  | ······//·Run·an·asynchronous·read·operation·with·a·timeout. | 144  | ······//·Run·an·asynchronous·read·operation·with·a·timeout. | 
| 174  | ······std::size_t·n·=·asio::async_read_until(socket, | 145  | ······std::size_t·n·=·asio::async_read_until(socket, | 
| 175  | ··········asio::dynamic_buffer(input_buffer),·'\n', | 146  | ··········asio::dynamic_buffer(input_buffer),·'\n', | 
| 176  | ··········close_after(asio::chrono::seconds(10),·socket)); | 147  | ··········close_after(std::chrono::seconds(10),·socket)); | 
| 177  |  | 148  |  | 
| 178  | ······std::string·line(input_buffer.substr(0,·n·-·1)); | 149  | ······std::string·line(input_buffer.substr(0,·n·-·1)); | 
| 179  | ······input_buffer.erase(0,·n); | 150  | ······input_buffer.erase(0,·n); | 
| 180  |  | 151  |  | 
| 181  | ······//·Keep·going·until·we·get·back·the·line·that·was·sent. | 152  | ······//·Keep·going·until·we·get·back·the·line·that·was·sent. | 
| 182  | ······if·(line·==·argv[3]) | 153  | ······if·(line·==·argv[3]) | 
| 183  | ········break; | 154  | ········break; | 
| 184  | ····} | 155  | ····} | 
| 185  |  | 156  |  | 
| 186  | ····asio::chrono::steady_clock::time_point·time_received·= | 157  | ····auto·time_received·=·std::chrono::steady_clock::now(); | 
| 187  | ······asio::chrono::steady_clock::now(); |  | 
| 188  |  | 158  |  | 
| 189  | ····std::cout·<<·"Round·trip·time:·"; | 159  | ····std::cout·<<·"Round·trip·time:·"; | 
| 190  | ····std::cout·<<·asio::chrono::duration_cast< | 160  | ····std::cout·<<·std::chrono::duration_cast< | 
| 191  | ······asio::chrono::microseconds>( | 161  | ······std::chrono::microseconds>( | 
| 192  | ········time_received·-·time_sent).count(); | 162  | ········time_received·-·time_sent).count(); | 
| 193  | ····std::cout·<<·"·microseconds\n"; | 163  | ····std::cout·<<·"·microseconds\n"; | 
| 194  | ··} | 164  | ··} | 
| 195  | ··catch·(std::exception&·e) | 165  | ··catch·(std::exception&·e) | 
| 196  | ··{ | 166  | ··{ | 
| 197  | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; | 167  | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; | 
| 198  | ··} | 168  | ··} | 
| 199  |  | 169  |  | 
| 200  | ··return·0; | 170  | ··return·0; | 
| 201  | } | 171  | } |