| src/examples/cpp03/timeouts/blocking_tcp_client.cpp | src/examples/cpp11/timeouts/blocking_tcp_client.cpp | 
| ⋮ | ⋮ | 
| 1  | // | 1  | // | 
| 2  | //·blocking_tcp_client.cpp | 2  | //·blocking_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/buffer.hpp" | 11  | #include·"asio/buffer.hpp" | 
| 12  | #include·"asio/connect.hpp" | 12  | #include·"asio/connect.hpp" | 
| 13  | #include·"asio/io_context.hpp" | 13  | #include·"asio/io_context.hpp" | 
| 14  | #include·"asio/ip/tcp.hpp" | 14  | #include·"asio/ip/tcp.hpp" | 
| 15  | #include·"asio/read_until.hpp" | 15  | #include·"asio/read_until.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·<string> | 20  | #include·<string> | 
| 21  | #include·<boost/lambda/bind.hpp> |  | 
| 22  | #include·<boost/lambda/lambda.hpp> |  | 
| 23  |  | 21  |  | 
| 24  | using·asio::ip::tcp; | 22  | using·asio::ip::tcp; | 
| 25  | using·boost::lambda::bind; |  | 
| 26  | using·boost::lambda::var; |  | 
| 27  | using·boost::lambda::_1; |  | 
| 28  | using·boost::lambda::_2; |  | 
| 29  |  | 23  |  | 
| 30  | //---------------------------------------------------------------------- | 24  | //---------------------------------------------------------------------- | 
| 31  |  | 25  |  | 
| 32  | // | 26  | // | 
| 33  | //·This·class·manages·socket·timeouts·by·running·the·io_context·using·the·timed | 27  | //·This·class·manages·socket·timeouts·by·running·the·io_context·using·the·timed | 
| 34  | //·io_context::run_for()·member·function.·Each·asynchronous·operation·is·given | 28  | //·io_context::run_for()·member·function.·Each·asynchronous·operation·is·given | 
| 35  | //·a·timeout·within·which·it·must·complete.·The·socket·operations·themselves | 29  | //·a·timeout·within·which·it·must·complete.·The·socket·operations·themselves | 
| 36  | //·use·boost::lambda·function·objects·as·completion·handlers.·For·a·given | 30  | //·use·lambdas·as·completion·handlers.·For·a·given·socket·operation,·the·client | 
| 37  | //·socket·operation,·the·client·object·runs·the·io_context·to·block·thread | 31  | //·object·runs·the·io_context·to·block·thread·execution·until·the·operation | 
| 38  | //·execution·until·the·operation·completes·or·the·timeout·is·reached.·If·the | 32  | //·completes·or·the·timeout·is·reached.·If·the·io_context::run_for()·function | 
| 39  | //·io_context::run_for()·function·times·out,·the·socket·is·closed·and·the | 33  | //·times·out,·the·socket·is·closed·and·the·outstanding·asynchronous·operation | 
| 40  | //·outstanding·asynchronous·operation·is·cancelled. | 34  | //·is·cancelled. | 
| 41  | // | 35  | // | 
| 42  | class·client | 36  | class·client | 
| 43  | { | 37  | { | 
| 44  | public: | 38  | public: | 
| 45  | ··client() |  | 
| 46  | ····:·socket_(io_context_) |  | 
| 47  | ··{ |  | 
| 48  | ··} |  | 
| 49  |  |  | 
| 50  | ··void·connect(const·std::string&·host,·const·std::string&·service, | 39  | ··void·connect(const·std::string&·host,·const·std::string&·service, | 
| 51  | ······asio::chrono::steady_clock::duration·timeout) | 40  | ······std::chrono::steady_clock::duration·timeout) | 
| 52  | ··{ | 41  | ··{ | 
| 53  | ····//·Resolve·the·host·name·and·service·to·a·list·of·endpoints. | 42  | ····//·Resolve·the·host·name·and·service·to·a·list·of·endpoints. | 
| 54  | ····tcp::resolver::results_type·endpoints·= | 43  | ····auto·endpoints·=·tcp::resolver(io_context_).resolve(host,·service); | 
| 55  | ······tcp::resolver(io_context_).resolve(host,·service); |  | 
| 56  |  | 44  |  | 
| 57  | ····//·Start·the·asynchronous·operation·itself.·The·boost::lambda·function | 45  | ····//·Start·the·asynchronous·operation·itself.·The·lambda·that·is·used·as·a | 
| 58  | ····//·object·is·used·as·a·callback·and·will·update·the·ec·variable·when·the | 46  | ····//·callback·will·update·the·error·variable·when·the·operation·completes. | 
| 59  | ····//·operation·completes.·The·blocking_udp_client.cpp·example·shows·how·you | 47  | ····//·The·blocking_udp_client.cpp·example·shows·how·you·can·use·std::bind | 
| 60  | ····//·can·use·boost::bind·rather·than·boost::lambda. | 48  | ····//·rather·than·a·lambda. | 
| 61  | ····asio::error_code·ec; | 49  | ····std::error_code·error; | 
| 62  | ····asio::async_connect(socket_,·endpoints,·var(ec)·=·_1); | 50  | ····asio::async_connect(socket_,·endpoints, | 
|   | 51  | ········[&](const·std::error_code&·result_error, | 
|   | 52  | ············const·tcp::endpoint&·/*result_endpoint*/) | 
|   | 53  | ········{ | 
|   | 54  | ··········error·=·result_error; | 
|   | 55  | ········}); | 
| 63  |  | 56  |  | 
| 64  | ····//·Run·the·operation·until·it·completes,·or·until·the·timeout. | 57  | ····//·Run·the·operation·until·it·completes,·or·until·the·timeout. | 
| 65  | ····run(timeout); | 58  | ····run(timeout); | 
| 66  |  | 59  |  | 
| 67  | ····//·Determine·whether·a·connection·was·successfully·established. | 60  | ····//·Determine·whether·a·connection·was·successfully·established. | 
| 68  | ····if·(ec) | 61  | ····if·(error) | 
| 69  | ······throw·asio::system_error(ec); | 62  | ······throw·std::system_error(error); | 
| 70  | ··} | 63  | ··} | 
| 71  |  | 64  |  | 
| 72  | ··std::string·read_line(asio::chrono::steady_clock::duration·timeout) | 65  | ··std::string·read_line(std::chrono::steady_clock::duration·timeout) | 
| 73  | ··{ | 66  | ··{ | 
| 74  | ····//·Start·the·asynchronous·operation.·The·boost::lambda·function·object·is | 67  | ····//·Start·the·asynchronous·operation.·The·lambda·that·is·used·as·a·callback | 
| 75  | ····//·used·as·a·callback·and·will·update·the·ec·variable·when·the·operation | 68  | ····//·will·update·the·error·and·n·variables·when·the·operation·completes.·The | 
| 76  | ····//·completes.·The·blocking_udp_client.cpp·example·shows·how·you·can·use | 69  | ····//·blocking_udp_client.cpp·example·shows·how·you·can·use·std::bind·rather | 
| 77  | ····//·boost::bind·rather·than·boost::lambda. | 70  | ····//·than·a·lambda. | 
| 78  | ····asio::error_code·ec; | 71  | ····std::error_code·error; | 
| 79  | ····std::size_t·n·=·0; | 72  | ····std::size_t·n·=·0; | 
| 80  | ····asio::async_read_until(socket_, | 73  | ····asio::async_read_until(socket_, | 
| 81  | ········asio::dynamic_buffer(input_buffer_), | 74  | ········asio::dynamic_buffer(input_buffer_),·'\n', | 
| 82  | ········'\n',·(var(ec)·=·_1,·var(n)·=·_2)); | 75  | ········[&](const·std::error_code&·result_error, | 
|   | 76  | ············std::size_t·result_n) | 
|   | 77  | ········{ | 
|   | 78  | ··········error·=·result_error; | 
|   | 79  | ··········n·=·result_n; | 
|   | 80  | ········}); | 
| 83  |  | 81  |  | 
| 84  | ····//·Run·the·operation·until·it·completes,·or·until·the·timeout. | 82  | ····//·Run·the·operation·until·it·completes,·or·until·the·timeout. | 
| 85  | ····run(timeout); | 83  | ····run(timeout); | 
| 86  |  | 84  |  | 
| 87  | ····//·Determine·whether·the·read·completed·successfully. | 85  | ····//·Determine·whether·the·read·completed·successfully. | 
| 88  | ····if·(ec) | 86  | ····if·(error) | 
| 89  | ······throw·asio::system_error(ec); | 87  | ······throw·std::system_error(error); | 
| 90  |  | 88  |  | 
| 91  | ····std::string·line(input_buffer_.substr(0,·n·-·1)); | 89  | ····std::string·line(input_buffer_.substr(0,·n·-·1)); | 
| 92  | ····input_buffer_.erase(0,·n); | 90  | ····input_buffer_.erase(0,·n); | 
| 93  | ····return·line; | 91  | ····return·line; | 
| 94  | ··} | 92  | ··} | 
| 95  |  | 93  |  | 
| 96  | ··void·write_line(const·std::string&·line, | 94  | ··void·write_line(const·std::string&·line, | 
| 97  | ······asio::chrono::steady_clock::duration·timeout) | 95  | ······std::chrono::steady_clock::duration·timeout) | 
| 98  | ··{ | 96  | ··{ | 
| 99  | ····std::string·data·=·line·+·"\n"; | 97  | ····std::string·data·=·line·+·"\n"; | 
| 100  |  | 98  |  | 
| 101  | ····//·Start·the·asynchronous·operation.·The·boost::lambda·function·object·is | 99  | ····//·Start·the·asynchronous·operation·itself.·The·lambda·that·is·used·as·a | 
| 102  | ····//·used·as·a·callback·and·will·update·the·ec·variable·when·the·operation | 100  | ····//·callback·will·update·the·error·variable·when·the·operation·completes. | 
| 103  | ····//·completes.·The·blocking_udp_client.cpp·example·shows·how·you·can·use | 101  | ····//·The·blocking_udp_client.cpp·example·shows·how·you·can·use·std::bind | 
| 104  | ····//·boost::bind·rather·than·boost::lambda. | 102  | ····//·rather·than·a·lambda. | 
| 105  | ····asio::error_code·ec; | 103  | ····std::error_code·error; | 
| 106  | ····asio::async_write(socket_,·asio::buffer(data),·var(ec)·=·_1); | 104  | ····asio::async_write(socket_,·asio::buffer(data), | 
|   | 105  | ········[&](const·std::error_code&·result_error, | 
|   | 106  | ············std::size_t·/*result_n*/) | 
|   | 107  | ········{ | 
|   | 108  | ··········error·=·result_error; | 
|   | 109  | ········}); | 
| 107  |  | 110  |  | 
| 108  | ····//·Run·the·operation·until·it·completes,·or·until·the·timeout. | 111  | ····//·Run·the·operation·until·it·completes,·or·until·the·timeout. | 
| 109  | ····run(timeout); | 112  | ····run(timeout); | 
| 110  |  | 113  |  | 
| 111  | ····//·Determine·whether·the·read·completed·successfully. | 114  | ····//·Determine·whether·the·read·completed·successfully. | 
| 112  | ····if·(ec) | 115  | ····if·(error) | 
| 113  | ······throw·asio::system_error(ec); | 116  | ······throw·std::system_error(error); | 
| 114  | ··} | 117  | ··} | 
| 115  |  | 118  |  | 
| 116  | private: | 119  | private: | 
| 117  | ··void·run(asio::chrono::steady_clock::duration·timeout) | 120  | ··void·run(std::chrono::steady_clock::duration·timeout) | 
| 118  | ··{ | 121  | ··{ | 
| 119  | ····//·Restart·the·io_context,·as·it·may·have·been·left·in·the·"stopped"·state | 122  | ····//·Restart·the·io_context,·as·it·may·have·been·left·in·the·"stopped"·state | 
| 120  | ····//·by·a·previous·operation. | 123  | ····//·by·a·previous·operation. | 
| 121  | ····io_context_.restart(); | 124  | ····io_context_.restart(); | 
| 122  |  | 125  |  | 
| 123  | ····//·Block·until·the·asynchronous·operation·has·completed,·or·timed·out.·If | 126  | ····//·Block·until·the·asynchronous·operation·has·completed,·or·timed·out.·If | 
| 124  | ····//·the·pending·asynchronous·operation·is·a·composed·operation,·the·deadline | 127  | ····//·the·pending·asynchronous·operation·is·a·composed·operation,·the·deadline | 
| 125  | ····//·applies·to·the·entire·operation,·rather·than·individual·operations·on | 128  | ····//·applies·to·the·entire·operation,·rather·than·individual·operations·on | 
| 126  | ····//·the·socket. | 129  | ····//·the·socket. | 
| 127  | ····io_context_.run_for(timeout); | 130  | ····io_context_.run_for(timeout); | 
| 128  |  | 131  |  | 
| 129  | ····//·If·the·asynchronous·operation·completed·successfully·then·the·io_context | 132  | ····//·If·the·asynchronous·operation·completed·successfully·then·the·io_context | 
| 130  | ····//·would·have·been·stopped·due·to·running·out·of·work.·If·it·was·not | 133  | ····//·would·have·been·stopped·due·to·running·out·of·work.·If·it·was·not | 
| 131  | ····//·stopped,·then·the·io_context::run_for·call·must·have·timed·out. | 134  | ····//·stopped,·then·the·io_context::run_for·call·must·have·timed·out. | 
| 132  | ····if·(!io_context_.stopped()) | 135  | ····if·(!io_context_.stopped()) | 
| 133  | ····{ | 136  | ····{ | 
| 134  | ······//·Close·the·socket·to·cancel·the·outstanding·asynchronous·operation. | 137  | ······//·Close·the·socket·to·cancel·the·outstanding·asynchronous·operation. | 
| 135  | ······socket_.close(); | 138  | ······socket_.close(); | 
| 136  |  | 139  |  | 
| 137  | ······//·Run·the·io_context·again·until·the·operation·completes. | 140  | ······//·Run·the·io_context·again·until·the·operation·completes. | 
| 138  | ······io_context_.run(); | 141  | ······io_context_.run(); | 
| 139  | ····} | 142  | ····} | 
| 140  | ··} | 143  | ··} | 
| 141  |  | 144  |  | 
| 142  | ··asio::io_context·io_context_; | 145  | ··asio::io_context·io_context_; | 
| 143  | ··tcp::socket·socket_; | 146  | ··tcp::socket·socket_{io_context_}; | 
| 144  | ··std::string·input_buffer_; | 147  | ··std::string·input_buffer_; | 
| 145  | }; | 148  | }; | 
| 146  |  | 149  |  | 
| 147  | //---------------------------------------------------------------------- | 150  | //---------------------------------------------------------------------- | 
| 148  |  | 151  |  | 
| 149  | int·main(int·argc,·char*·argv[]) | 152  | int·main(int·argc,·char*·argv[]) | 
| 150  | { | 153  | { | 
| 151  | ··try | 154  | ··try | 
| 152  | ··{ | 155  | ··{ | 
| 153  | ····if·(argc·!=·4) | 156  | ····if·(argc·!=·4) | 
| 154  | ····{ | 157  | ····{ | 
| 155  | ······std::cerr·<<·"Usage:·blocking_tcp_client·<host>·<port>·<message>\n"; | 158  | ······std::cerr·<<·"Usage:·blocking_tcp_client·<host>·<port>·<message>\n"; | 
| 156  | ······return·1; | 159  | ······return·1; | 
| 157  | ····} | 160  | ····} | 
| 158  |  | 161  |  | 
| 159  | ····client·c; | 162  | ····client·c; | 
| 160  | ····c.connect(argv[1],·argv[2],·asio::chrono::seconds(10)); | 163  | ····c.connect(argv[1],·argv[2],·std::chrono::seconds(10)); | 
| 161  |  | 164  |  | 
| 162  | ····asio::chrono::steady_clock::time_point·time_sent·= | 165  | ····auto·time_sent·=·std::chrono::steady_clock::now(); | 
| 163  | ······asio::chrono::steady_clock::now(); |  | 
| 164  |  | 166  |  | 
| 165  | ····c.write_line(argv[3],·asio::chrono::seconds(10)); | 167  | ····c.write_line(argv[3],·std::chrono::seconds(10)); | 
| 166  |  | 168  |  | 
| 167  | ····for·(;;) | 169  | ····for·(;;) | 
| 168  | ····{ | 170  | ····{ | 
| 169  | ······std::string·line·=·c.read_line(asio::chrono::seconds(10)); | 171  | ······std::string·line·=·c.read_line(std::chrono::seconds(10)); | 
| 170  |  | 172  |  | 
| 171  | ······//·Keep·going·until·we·get·back·the·line·that·was·sent. | 173  | ······//·Keep·going·until·we·get·back·the·line·that·was·sent. | 
| 172  | ······if·(line·==·argv[3]) | 174  | ······if·(line·==·argv[3]) | 
| 173  | ········break; | 175  | ········break; | 
| 174  | ····} | 176  | ····} | 
| 175  |  | 177  |  | 
| 176  | ····asio::chrono::steady_clock::time_point·time_received·= | 178  | ····auto·time_received·=·std::chrono::steady_clock::now(); | 
| 177  | ······asio::chrono::steady_clock::now(); |  | 
| 178  |  | 179  |  | 
| 179  | ····std::cout·<<·"Round·trip·time:·"; | 180  | ····std::cout·<<·"Round·trip·time:·"; | 
| 180  | ····std::cout·<<·asio::chrono::duration_cast< | 181  | ····std::cout·<<·std::chrono::duration_cast< | 
| 181  | ······asio::chrono::microseconds>( | 182  | ······std::chrono::microseconds>( | 
| 182  | ········time_received·-·time_sent).count(); | 183  | ········time_received·-·time_sent).count(); | 
| 183  | ····std::cout·<<·"·microseconds\n"; | 184  | ····std::cout·<<·"·microseconds\n"; | 
| 184  | ··} | 185  | ··} | 
| 185  | ··catch·(std::exception&·e) | 186  | ··catch·(std::exception&·e) | 
| 186  | ··{ | 187  | ··{ | 
| 187  | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; | 188  | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; | 
| 188  | ··} | 189  | ··} | 
| 189  |  | 190  |  | 
| 190  | ··return·0; | 191  | ··return·0; | 
| 191  | } | 192  | } |