src/​examples/​cpp03/​timeouts/​blocking_token_tcp_cl​ient.​cppsrc/​examples/​cpp11/​timeouts/​blocking_token_tcp_cl​ient.​cpp
1 /​/​1 /​/​
2 /​/​·​blocking_token_tcp_cl​ient.​cpp2 /​/​·​blocking_token_tcp_cl​ient.​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·​accompanying7 /​/​·​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<t​cp,​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·​as35 /​/​·​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_after37 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·​to53 /​/​·​The·​async_result·​template·​is·​specialised·​to·​allow·​the·​close_after·​token·​to
50 /​/​·​be·​used·​with·​asynchronous·​operations·​that·​have·​a·​completion·​signature·​of54 /​/​·​be·​used·​with·​asynchronous·​operations·​that·​have·​a·​completion·​signature·​of
51 /​/​·​void(error_code,​·​T)​.​·​Generalising·​this·​for·​all·​completion·​signature·​forms·​is55 /​/​·​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_af​ter,​·​void(asio:​:​error_code,​·​T)​>58 class·​async_result<close_af​ter,​·​void(std:​:​error_code,​·​T)​>
55 {59 {
56 public:​60 public:​
57 ··​/​/​·An·asynchronous·operation's·initiating·function·​automatically·creates·an61 ··​/​/​·The·initiate()​·function·is·used·to·launch·the·​asynchronous·operation·by
58 ··​/​/​·​completion_handler_ty​pe·object·from·the·token.​·This·function·object·is62 ··​/​/​·​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_ty​pe64 ··/​/​·​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_ty​pe(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(completi​on_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"·​state82 ····​/​/​·​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.​·​If86 ····​/​/​·​Block·​until·​the·​asynchronous·​operation·​has·​completed,​·​or·​timed·​out.​·​If
108 ····​/​/​·​the·​pending·​asynchronous·​operation·​is·​a·​composed·​operation,​·​the·​deadline87 ····​/​/​·​the·​pending·​asynchronous·​operation·​is·​a·​composed·​operation,​·​the·​deadline
109 ····​/​/​·​applies·​to·​the·​entire·​operation,​·​rather·​than·​individual·​operations·​on88 ····​/​/​·​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_context92 ····​/​/​·​If·​the·​asynchronous·​operation·​completed·​successfully·​then·​the·​io_context
114 ····​/​/​·​would·​have·​been·​stopped·​due·​to·​running·​out·​of·​work.​·​If·​it·​was·​not93 ····​/​/​·​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·​the94 ····​/​/​·​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·​asio110 }·​/​/​·​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 ··​try116 ··​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(sock​et,​145 ······​std:​:​size_t·​n·​=·​asio:​:​async_read_until(sock​et,​
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 }