src/​examples/​cpp03/​timeouts/​async_tcp_client.​cppsrc/​examples/​cpp11/​timeouts/​async_tcp_client.​cpp
1 /​/​1 /​/​
2 /​/​·​async_tcp_client.​cpp2 /​/​·​async_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·​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/​buffer.​hpp"11 #include·​"asio/​buffer.​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/​steady_timer.​hpp"15 #include·​"asio/​steady_timer.​hpp"
16 #include·​"asio/​write.​hpp"16 #include·​"asio/​write.​hpp"
17 #include·​<boost/​bind/​bind.​hpp>17 #include·​<functional>
18 #include·​<iostream>18 #include·​<iostream>
19 #include·​<string>19 #include·​<string>
20 20
21 using·​asio:​:​steady_timer;​21 using·​asio:​:​steady_timer;​
22 using·​asio:​:​ip:​:​tcp;​22 using·​asio:​:​ip:​:​tcp;​
23 using·​std:​:​placeholders:​:​_1;​
24 using·​std:​:​placeholders:​:​_2;​
23 25
24 /​/​26 /​/​
25 /​/​·​This·​class·​manages·​socket·​timeouts·​by·​applying·​the·​concept·​of·​a·​deadline.​27 /​/​·​This·​class·​manages·​socket·​timeouts·​by·​applying·​the·​concept·​of·​a·​deadline.​
26 /​/​·​Some·​asynchronous·​operations·​are·​given·​deadlines·​by·​which·​they·​must·​complete.​28 /​/​·​Some·​asynchronous·​operations·​are·​given·​deadlines·​by·​which·​they·​must·​complete.​
27 /​/​·​Deadlines·​are·​enforced·​by·​an·​"actor"·​that·​persists·​for·​the·​lifetime·​of·​the29 /​/​·​Deadlines·​are·​enforced·​by·​an·​"actor"·​that·​persists·​for·​the·​lifetime·​of·​the
28 /​/​·​client·​object:​30 /​/​·​client·​object:​
29 /​/​31 /​/​
30 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+32 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
31 /​/​··​|················​|33 /​/​··​|················​|
32 /​/​··​|·​check_deadline·​|<-​-​-​+34 /​/​··​|·​check_deadline·​|<-​-​-​+
33 /​/​··​|················​|····​|35 /​/​··​|················​|····​|
34 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+····​|·​async_wait()​36 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+····​|·​async_wait()​
35 /​/​··············​|·········​|37 /​/​··············​|·········​|
36 /​/​··············​+-​-​-​-​-​-​-​-​-​+38 /​/​··············​+-​-​-​-​-​-​-​-​-​+
37 /​/​39 /​/​
38 /​/​·​If·​the·​deadline·​actor·​determines·​that·​the·​deadline·​has·​expired,​·​the·​socket40 /​/​·​If·​the·​deadline·​actor·​determines·​that·​the·​deadline·​has·​expired,​·​the·​socket
39 /​/​·​is·​closed·​and·​any·​outstanding·​operations·​are·​consequently·​cancelled.​41 /​/​·​is·​closed·​and·​any·​outstanding·​operations·​are·​consequently·​cancelled.​
40 /​/​42 /​/​
41 /​/​·​Connection·​establishment·​involves·​trying·​each·​endpoint·​in·​turn·​until·​a43 /​/​·​Connection·​establishment·​involves·​trying·​each·​endpoint·​in·​turn·​until·​a
42 /​/​·​connection·​is·​successful,​·​or·​the·​available·​endpoints·​are·​exhausted.​·​If·​the44 /​/​·​connection·​is·​successful,​·​or·​the·​available·​endpoints·​are·​exhausted.​·​If·​the
43 /​/​·​deadline·​actor·​closes·​the·​socket,​·​the·​connect·​actor·​is·​woken·​up·​and·​moves·​to45 /​/​·​deadline·​actor·​closes·​the·​socket,​·​the·​connect·​actor·​is·​woken·​up·​and·​moves·​to
44 /​/​·​the·​next·​endpoint.​46 /​/​·​the·​next·​endpoint.​
45 /​/​47 /​/​
46 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+48 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
47 /​/​··​|···············​|49 /​/​··​|···············​|
48 /​/​··​|·​start_connect·​|<-​-​-​+50 /​/​··​|·​start_connect·​|<-​-​-​+
49 /​/​··​|···············​|····​|51 /​/​··​|···············​|····​|
50 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+····​|52 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+····​|
51 /​/​···········​|···········​|53 /​/​···········​|···········​|
52 /​/​··​async_-​··​|····​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+54 /​/​··​async_-​··​|····​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
53 /​/​·​connect()​·​|····​|················​|55 /​/​·​connect()​·​|····​|················​|
54 /​/​···········​+-​-​-​>|·​handle_connect·​|56 /​/​···········​+-​-​-​>|·​handle_connect·​|
55 /​/​················​|················​|57 /​/​················​|················​|
56 /​/​················​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+58 /​/​················​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
57 /​/​··························​:​59 /​/​··························​:​
58 /​/​·​Once·​a·​connection·​is·····​:​60 /​/​·​Once·​a·​connection·​is·····​:​
59 /​/​·​made,​·​the·​connect········​:​61 /​/​·​made,​·​the·​connect········​:​
60 /​/​·​actor·​forks·​in·​two·​-​·····​:​62 /​/​·​actor·​forks·​in·​two·​-​·····​:​
61 /​/​··························​:​63 /​/​··························​:​
62 /​/​·​an·​actor·​for·​reading·····​:​·······​and·​an·​actor·​for64 /​/​·​an·​actor·​for·​reading·····​:​·······​and·​an·​actor·​for
63 /​/​·​inbound·​messages:​········​:​·······​sending·​heartbeats:​65 /​/​·​inbound·​messages:​········​:​·······​sending·​heartbeats:​
64 /​/​··························​:​66 /​/​··························​:​
65 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​+··········​:​··········​+-​-​-​-​-​-​-​-​-​-​-​-​-​+67 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​+··········​:​··········​+-​-​-​-​-​-​-​-​-​-​-​-​-​+
66 /​/​··​|············​|<-​·​-​·​-​·​-​·​-​+-​·​-​·​-​·​-​·​-​>|·············​|68 /​/​··​|············​|<-​·​-​·​-​·​-​·​-​+-​·​-​·​-​·​-​·​-​>|·············​|
67 /​/​··​|·​start_read·​|·····················​|·​start_write·​|<-​-​-​+69 /​/​··​|·​start_read·​|·····················​|·​start_write·​|<-​-​-​+
68 /​/​··​|············​|<-​-​-​+················​|·············​|····​|70 /​/​··​|············​|<-​-​-​+················​|·············​|····​|
69 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​+····​|················​+-​-​-​-​-​-​-​-​-​-​-​-​-​+····​|·​async_wait()​71 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​+····​|················​+-​-​-​-​-​-​-​-​-​-​-​-​-​+····​|·​async_wait()​
70 /​/​··········​|·········​|························​|··········​|72 /​/​··········​|·········​|························​|··········​|
71 /​/​··​async_-​·​|····​+-​-​-​-​-​-​-​-​-​-​-​-​-​+·······​async_-​·​|····​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+73 /​/​··​async_-​·​|····​+-​-​-​-​-​-​-​-​-​-​-​-​-​+·······​async_-​·​|····​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
72 /​/​···​read_-​·​|····​|·············​|·······​write()​·​|····​|··············​|74 /​/​···​read_-​·​|····​|·············​|·······​write()​·​|····​|··············​|
73 /​/​··​until()​·​+-​-​-​>|·​handle_read·​|···············​+-​-​-​>|·​handle_write·​|75 /​/​··​until()​·​+-​-​-​>|·​handle_read·​|···············​+-​-​-​>|·​handle_write·​|
74 /​/​···············​|·············​|····················​|··············​|76 /​/​···············​|·············​|····················​|··············​|
75 /​/​···············​+-​-​-​-​-​-​-​-​-​-​-​-​-​+····················​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+77 /​/​···············​+-​-​-​-​-​-​-​-​-​-​-​-​-​+····················​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
76 /​/​78 /​/​
77 /​/​·​The·​input·​actor·​reads·​messages·​from·​the·​socket,​·​where·​messages·​are·​delimited79 /​/​·​The·​input·​actor·​reads·​messages·​from·​the·​socket,​·​where·​messages·​are·​delimited
78 /​/​·​by·​the·​newline·​character.​·​The·​deadline·​for·​a·​complete·​message·​is·​30·​seconds.​80 /​/​·​by·​the·​newline·​character.​·​The·​deadline·​for·​a·​complete·​message·​is·​30·​seconds.​
79 /​/​81 /​/​
80 /​/​·​The·​heartbeat·​actor·​sends·​a·​heartbeat·​(a·​message·​that·​consists·​of·​a·​single82 /​/​·​The·​heartbeat·​actor·​sends·​a·​heartbeat·​(a·​message·​that·​consists·​of·​a·​single
81 /​/​·​newline·​character)​·​every·​10·​seconds.​·​In·​this·​example,​·​no·​deadline·​is·​applied83 /​/​·​newline·​character)​·​every·​10·​seconds.​·​In·​this·​example,​·​no·​deadline·​is·​applied
82 /​/​·​to·​message·​sending.​84 /​/​·​to·​message·​sending.​
83 /​/​85 /​/​
84 class·​client86 class·​client
85 {87 {
86 public:​88 public:​
87 ··​client(asio:​:​io_context&·​io_context)​89 ··​client(asio:​:​io_context&·​io_context)​
88 ····​:​·​stopped_(false)​,​90 ····​:​·​socket_(io_context)​,​
89 ······socket_(io_context)​,​
90 ······​deadline_(io_context)​,​91 ······​deadline_(io_context)​,​
91 ······​heartbeat_timer_(io_c​ontext)​92 ······​heartbeat_timer_(io_c​ontext)​
92 ··​{93 ··​{
93 ··​}94 ··​}
94 95
95 ··​/​/​·​Called·​by·​the·​user·​of·​the·​client·​class·​to·​initiate·​the·​connection·​process.​96 ··​/​/​·​Called·​by·​the·​user·​of·​the·​client·​class·​to·​initiate·​the·​connection·​process.​
96 ··​/​/​·​The·​endpoints·​will·​have·​been·​obtained·​using·​a·​tcp:​:​resolver.​97 ··​/​/​·​The·​endpoints·​will·​have·​been·​obtained·​using·​a·​tcp:​:​resolver.​
97 ··​void·​start(tcp:​:​resolver:​:​results_type·​endpoints)​98 ··​void·​start(tcp:​:​resolver:​:​results_type·​endpoints)​
98 ··​{99 ··​{
99 ····​/​/​·​Start·​the·​connect·​actor.​100 ····​/​/​·​Start·​the·​connect·​actor.​
100 ····​endpoints_·​=·​endpoints;​101 ····​endpoints_·​=·​endpoints;​
101 ····​start_connect(endpoin​ts_.​begin()​)​;​102 ····​start_connect(endpoin​ts_.​begin()​)​;​
102 103
103 ····​/​/​·​Start·​the·​deadline·​actor.​·​You·​will·​note·​that·​we're·​not·​setting·​any104 ····​/​/​·​Start·​the·​deadline·​actor.​·​You·​will·​note·​that·​we're·​not·​setting·​any
104 ····​/​/​·​particular·​deadline·​here.​·​Instead,​·​the·​connect·​and·​input·​actors·​will105 ····​/​/​·​particular·​deadline·​here.​·​Instead,​·​the·​connect·​and·​input·​actors·​will
105 ····​/​/​·​update·​the·​deadline·​prior·​to·​each·​asynchronous·​operation.​106 ····​/​/​·​update·​the·​deadline·​prior·​to·​each·​asynchronous·​operation.​
106 ····​deadline_.​async_wait(boost:​:​bind(&client:​:​check_deadline,​·​this)​)​;​107 ····​deadline_.​async_wait(std:​:​bind(&client:​:​check_deadline,​·​this)​)​;​
107 ··​}108 ··​}
108 109
109 ··​/​/​·​This·​function·​terminates·​all·​the·​actors·​to·​shut·​down·​the·​connection.​·​It110 ··​/​/​·​This·​function·​terminates·​all·​the·​actors·​to·​shut·​down·​the·​connection.​·​It
110 ··​/​/​·​may·​be·​called·​by·​the·​user·​of·​the·​client·​class,​·​or·​by·​the·​class·​itself·​in111 ··​/​/​·​may·​be·​called·​by·​the·​user·​of·​the·​client·​class,​·​or·​by·​the·​class·​itself·​in
111 ··​/​/​·​response·​to·​graceful·​termination·​or·​an·​unrecoverable·​error.​112 ··​/​/​·​response·​to·​graceful·​termination·​or·​an·​unrecoverable·​error.​
112 ··​void·​stop()​113 ··​void·​stop()​
113 ··​{114 ··​{
114 ····​stopped_·​=·​true;​115 ····​stopped_·​=·​true;​
115 ····asio:​:​error_code·​ignored_ec;​116 ····​std:​:​error_code·​ignored_error;​
116 ····​socket_.​close(ignored_ec)​;​117 ····​socket_.​close(ignored_error)​;​
117 ····​deadline_.​cancel()​;​118 ····​deadline_.​cancel()​;​
118 ····​heartbeat_timer_.​cancel()​;​119 ····​heartbeat_timer_.​cancel()​;​
119 ··​}120 ··​}
120 121
121 private:​122 private:​
122 ··​void·​start_connect(tcp:​:​resolver:​:​results_type:​:​iterator·​endpoint_iter)​123 ··​void·​start_connect(tcp:​:​resolver:​:​results_type:​:​iterator·​endpoint_iter)​
123 ··​{124 ··​{
124 ····​if·​(endpoint_iter·​!=·​endpoints_.​end()​)​125 ····​if·​(endpoint_iter·​!=·​endpoints_.​end()​)​
125 ····​{126 ····​{
126 ······​std:​:​cout·​<<·​"Trying·​"·​<<·​endpoint_iter-​>endpoint()​·​<<·​".​.​.​\n";​127 ······​std:​:​cout·​<<·​"Trying·​"·​<<·​endpoint_iter-​>endpoint()​·​<<·​".​.​.​\n";​
127 128
128 ······​/​/​·​Set·​a·​deadline·​for·​the·​connect·​operation.​129 ······​/​/​·​Set·​a·​deadline·​for·​the·​connect·​operation.​
129 ······​deadline_.​expires_after(asio:​:​chrono:​:​seconds(60)​)​;​130 ······​deadline_.​expires_after(std:​:​chrono:​:​seconds(60)​)​;​
130 131
131 ······​/​/​·​Start·​the·​asynchronous·​connect·​operation.​132 ······​/​/​·​Start·​the·​asynchronous·​connect·​operation.​
132 ······​socket_.​async_connect(endpoin​t_iter-​>endpoint()​,​133 ······​socket_.​async_connect(endpoin​t_iter-​>endpoint()​,​
133 ··········boost:​:​bind(&client:​:​handle_connect,​·this,​134 ··········​std:​:​bind(&client:​:​handle_connect,​
134 ············boost:​:​placeholders:​:​_1,​·​endpoint_iter)​)​;​135 ············​this,​·_1,​·​endpoint_iter)​)​;​
135 ····​}136 ····​}
136 ····​else137 ····​else
137 ····​{138 ····​{
138 ······​/​/​·​There·​are·​no·​more·​endpoints·​to·​try.​·​Shut·​down·​the·​client.​139 ······​/​/​·​There·​are·​no·​more·​endpoints·​to·​try.​·​Shut·​down·​the·​client.​
139 ······​stop()​;​140 ······​stop()​;​
140 ····​}141 ····​}
141 ··​}142 ··​}
142 143
143 ··​void·​handle_connect(const·asio:​:​error_code&·​ec,​144 ··​void·​handle_connect(const·​std:​:​error_code&·​error,​
144 ······​tcp:​:​resolver:​:​results_type:​:​iterator·​endpoint_iter)​145 ······​tcp:​:​resolver:​:​results_type:​:​iterator·​endpoint_iter)​
145 ··​{146 ··​{
146 ····​if·​(stopped_)​147 ····​if·​(stopped_)​
147 ······​return;​148 ······​return;​
148 149
149 ····​/​/​·​The·​async_connect()​·​function·​automatically·​opens·​the·​socket·​at·​the·​start150 ····​/​/​·​The·​async_connect()​·​function·​automatically·​opens·​the·​socket·​at·​the·​start
150 ····​/​/​·​of·​the·​asynchronous·​operation.​·​If·​the·​socket·​is·​closed·​at·​this·​time·​then151 ····​/​/​·​of·​the·​asynchronous·​operation.​·​If·​the·​socket·​is·​closed·​at·​this·​time·​then
151 ····​/​/​·​the·​timeout·​handler·​must·​have·​run·​first.​152 ····​/​/​·​the·​timeout·​handler·​must·​have·​run·​first.​
152 ····​if·​(!socket_.​is_open()​)​153 ····​if·​(!socket_.​is_open()​)​
153 ····​{154 ····​{
154 ······​std:​:​cout·​<<·​"Connect·​timed·​out\n";​155 ······​std:​:​cout·​<<·​"Connect·​timed·​out\n";​
155 156
156 ······​/​/​·​Try·​the·​next·​available·​endpoint.​157 ······​/​/​·​Try·​the·​next·​available·​endpoint.​
157 ······​start_connect(++endpo​int_iter)​;​158 ······​start_connect(++endpo​int_iter)​;​
158 ····​}159 ····​}
159 160
160 ····​/​/​·​Check·​if·​the·​connect·​operation·​failed·​before·​the·​deadline·​expired.​161 ····​/​/​·​Check·​if·​the·​connect·​operation·​failed·​before·​the·​deadline·​expired.​
161 ····​else·​if·​(ec)​162 ····​else·​if·​(error)​
162 ····​{163 ····​{
163 ······​std:​:​cout·​<<·​"Connect·​error:​·​"·​<<·​ec.​message()​·​<<·​"\n";​164 ······​std:​:​cout·​<<·​"Connect·​error:​·​"·​<<·​error.​message()​·​<<·​"\n";​
164 165
165 ······​/​/​·​We·​need·​to·​close·​the·​socket·​used·​in·​the·​previous·​connection·​attempt166 ······​/​/​·​We·​need·​to·​close·​the·​socket·​used·​in·​the·​previous·​connection·​attempt
166 ······​/​/​·​before·​starting·​a·​new·​one.​167 ······​/​/​·​before·​starting·​a·​new·​one.​
167 ······​socket_.​close()​;​168 ······​socket_.​close()​;​
168 169
169 ······​/​/​·​Try·​the·​next·​available·​endpoint.​170 ······​/​/​·​Try·​the·​next·​available·​endpoint.​
170 ······​start_connect(++endpo​int_iter)​;​171 ······​start_connect(++endpo​int_iter)​;​
171 ····​}172 ····​}
172 173
173 ····​/​/​·​Otherwise·​we·​have·​successfully·​established·​a·​connection.​174 ····​/​/​·​Otherwise·​we·​have·​successfully·​established·​a·​connection.​
174 ····​else175 ····​else
175 ····​{176 ····​{
176 ······​std:​:​cout·​<<·​"Connected·​to·​"·​<<·​endpoint_iter-​>endpoint()​·​<<·​"\n";​177 ······​std:​:​cout·​<<·​"Connected·​to·​"·​<<·​endpoint_iter-​>endpoint()​·​<<·​"\n";​
177 178
178 ······​/​/​·​Start·​the·​input·​actor.​179 ······​/​/​·​Start·​the·​input·​actor.​
179 ······​start_read()​;​180 ······​start_read()​;​
180 181
181 ······​/​/​·​Start·​the·​heartbeat·​actor.​182 ······​/​/​·​Start·​the·​heartbeat·​actor.​
182 ······​start_write()​;​183 ······​start_write()​;​
183 ····​}184 ····​}
184 ··​}185 ··​}
185 186
186 ··​void·​start_read()​187 ··​void·​start_read()​
187 ··​{188 ··​{
188 ····​/​/​·​Set·​a·​deadline·​for·​the·​read·​operation.​189 ····​/​/​·​Set·​a·​deadline·​for·​the·​read·​operation.​
189 ····​deadline_.​expires_after(asio:​:​chrono:​:​seconds(30)​)​;​190 ····​deadline_.​expires_after(std:​:​chrono:​:​seconds(30)​)​;​
190 191
191 ····​/​/​·​Start·​an·​asynchronous·​operation·​to·​read·​a·​newline-​delimited·​message.​192 ····​/​/​·​Start·​an·​asynchronous·​operation·​to·​read·​a·​newline-​delimited·​message.​
192 ····​asio:​:​async_read_until(sock​et_,​193 ····​asio:​:​async_read_until(sock​et_,​
193 ········​asio:​:​dynamic_buffer(input_​buffer_)​,​·​'\n',​194 ········​asio:​:​dynamic_buffer(input_​buffer_)​,​·​'\n',​
194 ········boost:​:​bind(&client:​:​handle_read,​·​this,​195 ········​std:​:​bind(&client:​:​handle_read,​·​this,​·_1,​·_2)​)​;​
195 ··········boost:​:​placeholders:​:​_1,​·boost:​:​placeholders:​:​_2)​)​;​
196 ··​}196 ··​}
197 197
198 ··​void·​handle_read(const·asio:​:​error_code&·​ec,​·​std:​:​size_t·​n)​198 ··​void·​handle_read(const·​std:​:​error_code&·​error,​·​std:​:​size_t·​n)​
199 ··​{199 ··​{
200 ····​if·​(stopped_)​200 ····​if·​(stopped_)​
201 ······​return;​201 ······​return;​
202 202
203 ····​if·​(!ec)​203 ····​if·​(!error)​
204 ····​{204 ····​{
205 ······​/​/​·​Extract·​the·​newline-​delimited·​message·​from·​the·​buffer.​205 ······​/​/​·​Extract·​the·​newline-​delimited·​message·​from·​the·​buffer.​
206 ······​std:​:​string·​line(input_buffer_.​substr(0,​·​n·​-​·​1)​)​;​206 ······​std:​:​string·​line(input_buffer_.​substr(0,​·​n·​-​·​1)​)​;​
207 ······​input_buffer_.​erase(0,​·​n)​;​207 ······​input_buffer_.​erase(0,​·​n)​;​
208 208
209 ······​/​/​·​Empty·​messages·​are·​heartbeats·​and·​so·​ignored.​209 ······​/​/​·​Empty·​messages·​are·​heartbeats·​and·​so·​ignored.​
210 ······​if·​(!line.​empty()​)​210 ······​if·​(!line.​empty()​)​
211 ······​{211 ······​{
212 ········​std:​:​cout·​<<·​"Received:​·​"·​<<·​line·​<<·​"\n";​212 ········​std:​:​cout·​<<·​"Received:​·​"·​<<·​line·​<<·​"\n";​
213 ······​}213 ······​}
214 214
215 ······​start_read()​;​215 ······​start_read()​;​
216 ····​}216 ····​}
217 ····​else217 ····​else
218 ····​{218 ····​{
219 ······​std:​:​cout·​<<·​"Error·​on·​receive:​·​"·​<<·​ec.​message()​·​<<·​"\n";​219 ······​std:​:​cout·​<<·​"Error·​on·​receive:​·​"·​<<·​error.​message()​·​<<·​"\n";​
220 220
221 ······​stop()​;​221 ······​stop()​;​
222 ····​}222 ····​}
223 ··​}223 ··​}
224 224
225 ··​void·​start_write()​225 ··​void·​start_write()​
226 ··​{226 ··​{
227 ····​if·​(stopped_)​227 ····​if·​(stopped_)​
228 ······​return;​228 ······​return;​
229 229
230 ····​/​/​·​Start·​an·​asynchronous·​operation·​to·​send·​a·​heartbeat·​message.​230 ····​/​/​·​Start·​an·​asynchronous·​operation·​to·​send·​a·​heartbeat·​message.​
231 ····​asio:​:​async_write(socket_,​·​asio:​:​buffer("\n",​·​1)​,​231 ····​asio:​:​async_write(socket_,​·​asio:​:​buffer("\n",​·​1)​,​
232 ········boost:​:​bind(&client:​:​handle_write,​·​this,​·boost:​:​placeholders:​:​_1)​)​;​232 ········​std:​:​bind(&client:​:​handle_write,​·​this,​·​_1)​)​;​
233 ··​}233 ··​}
234 234
235 ··​void·​handle_write(const·asio:​:​error_code&·​ec)​235 ··​void·​handle_write(const·​std:​:​error_code&·​error)​
236 ··​{236 ··​{
237 ····​if·​(stopped_)​237 ····​if·​(stopped_)​
238 ······​return;​238 ······​return;​
239 239
240 ····​if·​(!ec)​240 ····​if·​(!error)​
241 ····​{241 ····​{
242 ······​/​/​·​Wait·​10·​seconds·​before·​sending·​the·​next·​heartbeat.​242 ······​/​/​·​Wait·​10·​seconds·​before·​sending·​the·​next·​heartbeat.​
243 ······​heartbeat_timer_.​expires_after(asio:​:​chrono:​:​seconds(10)​)​;​243 ······​heartbeat_timer_.​expires_after(std:​:​chrono:​:​seconds(10)​)​;​
244 ······​heartbeat_timer_.​async_wait(boost:​:​bind(&client:​:​start_write,​·​this)​)​;​244 ······​heartbeat_timer_.​async_wait(std:​:​bind(&client:​:​start_write,​·​this)​)​;​
245 ····​}245 ····​}
246 ····​else246 ····​else
247 ····​{247 ····​{
248 ······​std:​:​cout·​<<·​"Error·​on·​heartbeat:​·​"·​<<·​ec.​message()​·​<<·​"\n";​248 ······​std:​:​cout·​<<·​"Error·​on·​heartbeat:​·​"·​<<·​error.​message()​·​<<·​"\n";​
249 249
250 ······​stop()​;​250 ······​stop()​;​
251 ····​}251 ····​}
252 ··​}252 ··​}
253 253
254 ··​void·​check_deadline()​254 ··​void·​check_deadline()​
255 ··​{255 ··​{
256 ····​if·​(stopped_)​256 ····​if·​(stopped_)​
257 ······​return;​257 ······​return;​
258 258
259 ····​/​/​·​Check·​whether·​the·​deadline·​has·​passed.​·​We·​compare·​the·​deadline·​against259 ····​/​/​·​Check·​whether·​the·​deadline·​has·​passed.​·​We·​compare·​the·​deadline·​against
260 ····​/​/​·​the·​current·​time·​since·​a·​new·​asynchronous·​operation·​may·​have·​moved·​the260 ····​/​/​·​the·​current·​time·​since·​a·​new·​asynchronous·​operation·​may·​have·​moved·​the
261 ····​/​/​·​deadline·​before·​this·​actor·​had·​a·​chance·​to·​run.​261 ····​/​/​·​deadline·​before·​this·​actor·​had·​a·​chance·​to·​run.​
262 ····​if·​(deadline_.​expiry()​·​<=·​steady_timer:​:​clock_type:​:​now()​)​262 ····​if·​(deadline_.​expiry()​·​<=·​steady_timer:​:​clock_type:​:​now()​)​
263 ····​{263 ····​{
264 ······​/​/​·​The·​deadline·​has·​passed.​·​The·​socket·​is·​closed·​so·​that·​any·​outstanding264 ······​/​/​·​The·​deadline·​has·​passed.​·​The·​socket·​is·​closed·​so·​that·​any·​outstanding
265 ······​/​/​·​asynchronous·​operations·​are·​cancelled.​265 ······​/​/​·​asynchronous·​operations·​are·​cancelled.​
266 ······​socket_.​close()​;​266 ······​socket_.​close()​;​
267 267
268 ······​/​/​·​There·​is·​no·​longer·​an·​active·​deadline.​·​The·​expiry·​is·​set·​to·​the268 ······​/​/​·​There·​is·​no·​longer·​an·​active·​deadline.​·​The·​expiry·​is·​set·​to·​the
269 ······​/​/​·​maximum·​time·​point·​so·​that·​the·​actor·​takes·​no·​action·​until·​a·​new269 ······​/​/​·​maximum·​time·​point·​so·​that·​the·​actor·​takes·​no·​action·​until·​a·​new
270 ······​/​/​·​deadline·​is·​set.​270 ······​/​/​·​deadline·​is·​set.​
271 ······​deadline_.​expires_at(steady_tim​er:​:​time_point:​:​max()​)​;​271 ······​deadline_.​expires_at(steady_tim​er:​:​time_point:​:​max()​)​;​
272 ····​}272 ····​}
273 273
274 ····​/​/​·​Put·​the·​actor·​back·​to·​sleep.​274 ····​/​/​·​Put·​the·​actor·​back·​to·​sleep.​
275 ····​deadline_.​async_wait(boost:​:​bind(&client:​:​check_deadline,​·​this)​)​;​275 ····​deadline_.​async_wait(std:​:​bind(&client:​:​check_deadline,​·​this)​)​;​
276 ··​}276 ··​}
277 277
278 private:​278 private:​
279 ··​bool·​stopped_;​279 ··​bool·​stopped_·=·false;​
280 ··​tcp:​:​resolver:​:​results_type·​endpoints_;​280 ··​tcp:​:​resolver:​:​results_type·​endpoints_;​
281 ··​tcp:​:​socket·​socket_;​281 ··​tcp:​:​socket·​socket_;​
282 ··​std:​:​string·​input_buffer_;​282 ··​std:​:​string·​input_buffer_;​
283 ··​steady_timer·​deadline_;​283 ··​steady_timer·​deadline_;​
284 ··​steady_timer·​heartbeat_timer_;​284 ··​steady_timer·​heartbeat_timer_;​
285 };​285 };​
286 286
287 int·​main(int·​argc,​·​char*·​argv[])​287 int·​main(int·​argc,​·​char*·​argv[])​
288 {288 {
289 ··​try289 ··​try
290 ··​{290 ··​{
291 ····​if·​(argc·​!=·​3)​291 ····​if·​(argc·​!=·​3)​
292 ····​{292 ····​{
293 ······​std:​:​cerr·​<<·​"Usage:​·​client·​<host>·​<port>\n";​293 ······​std:​:​cerr·​<<·​"Usage:​·​client·​<host>·​<port>\n";​
294 ······​return·​1;​294 ······​return·​1;​
295 ····​}295 ····​}
296 296
297 ····​asio:​:​io_context·​io_context;​297 ····​asio:​:​io_context·​io_context;​
298 ····​tcp:​:​resolver·​r(io_context)​;​298 ····​tcp:​:​resolver·​r(io_context)​;​
299 ····​client·​c(io_context)​;​299 ····​client·​c(io_context)​;​
300 300
301 ····​c.​start(r.​resolve(argv[1],​·​argv[2])​)​;​301 ····​c.​start(r.​resolve(argv[1],​·​argv[2])​)​;​
302 302
303 ····​io_context.​run()​;​303 ····​io_context.​run()​;​
304 ··​}304 ··​}
305 ··​catch·​(std:​:​exception&·​e)​305 ··​catch·​(std:​:​exception&·​e)​
306 ··​{306 ··​{
307 ····​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​"\n";​307 ····​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​"\n";​
308 ··​}308 ··​}
309 309
310 ··​return·​0;​310 ··​return·​0;​
311 }311 }