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