src/​examples/​cpp03/​timeouts/​server.​cppsrc/​examples/​cpp11/​timeouts/​server.​cpp
1 /​/​1 /​/​
2 /​/​·​server.​cpp2 /​/​·​server.​cpp
3 /​/​·​~~~~~~~~~~3 /​/​·​~~~~~~~~~~
4 /​/​4 /​/​
5 /​/​·​Copyright·​(c)​·​2003-​2022·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​5 /​/​·​Copyright·​(c)​·​2003-​2022·​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·​<algorithm>11 #include·​<algorithm>
12 #include·​<cstdlib>12 #include·​<cstdlib>
13 #include·​<deque>13 #include·​<deque>
14 #include·​<iostream>14 #include·​<iostream>
15 #include·​<memory>
15 #include·​<set>16 #include·​<set>
16 #include·​<string>17 #include·​<string>
17 #include·​<boost/​bind/​bind.​hpp>
18 #include·​<boost/​shared_ptr.​hpp>
19 #include·​<boost/​enable_shared_from_th​is.​hpp>
20 #include·​"asio/​buffer.​hpp"18 #include·​"asio/​buffer.​hpp"
21 #include·​"asio/​io_context.​hpp"19 #include·​"asio/​io_context.​hpp"
22 #include·​"asio/​ip/​tcp.​hpp"20 #include·​"asio/​ip/​tcp.​hpp"
23 #include·​"asio/​ip/​udp.​hpp"21 #include·​"asio/​ip/​udp.​hpp"
24 #include·​"asio/​read_until.​hpp"22 #include·​"asio/​read_until.​hpp"
25 #include·​"asio/​steady_timer.​hpp"23 #include·​"asio/​steady_timer.​hpp"
26 #include·​"asio/​write.​hpp"24 #include·​"asio/​write.​hpp"
27 25
28 using·​asio:​:​steady_timer;​26 using·​asio:​:​steady_timer;​
29 using·​asio:​:​ip:​:​tcp;​27 using·​asio:​:​ip:​:​tcp;​
30 using·​asio:​:​ip:​:​udp;​28 using·​asio:​:​ip:​:​udp;​
31 29
32 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​30 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
33 31
34 class·​subscriber32 class·​subscriber
35 {33 {
36 public:​34 public:​
37 ··​virtual·​~subscriber()​·{}35 ··​virtual·​~subscriber()​·=·default;​
38 ··​virtual·​void·​deliver(const·​std:​:​string&·​msg)​·​=·​0;​36 ··​virtual·​void·​deliver(const·​std:​:​string&·​msg)​·​=·​0;​
39 };​37 };​
40 38
41 typedef·boost:​:​shared_ptr<subscriber​>·​subscriber_ptr;​39 typedef·​std:​:​shared_ptr<subscriber​>·​subscriber_ptr;​
42 40
43 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​41 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
44 42
45 class·​channel43 class·​channel
46 {44 {
47 public:​45 public:​
48 ··​void·​join(subscriber_ptr·​subscriber)​46 ··​void·​join(subscriber_ptr·​subscriber)​
49 ··​{47 ··​{
50 ····​subscribers_.​insert(subscriber)​;​48 ····​subscribers_.​insert(subscriber)​;​
51 ··​}49 ··​}
52 50
53 ··​void·​leave(subscriber_ptr·​subscriber)​51 ··​void·​leave(subscriber_ptr·​subscriber)​
54 ··​{52 ··​{
55 ····​subscribers_.​erase(subscriber)​;​53 ····​subscribers_.​erase(subscriber)​;​
56 ··​}54 ··​}
57 55
58 ··​void·​deliver(const·​std:​:​string&·​msg)​56 ··​void·​deliver(const·​std:​:​string&·​msg)​
59 ··​{57 ··​{
60 ····std:​:​for_each(subscribers_​.​begin()​,​·​subscribers_.​end()​,​58 ····​for·(const·auto&·s·:​·​subscribers_)​
61 ········boost:​:​bind(&subscriber:​:​deliver,​59 ····{
62 ··········boost:​:​placeholders:​:​_1,​·boost:​:​ref(msg)​)​)​;​60 ······​s-​>deliver(msg)​;​
61 ····​}
63 ··​}62 ··​}
64 63
65 private:​64 private:​
66 ··​std:​:​set<subscriber_ptr>·​subscribers_;​65 ··​std:​:​set<subscriber_ptr>·​subscribers_;​
67 };​66 };​
68 67
69 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​68 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
70 69
71 /​/​70 /​/​
72 /​/​·​This·​class·​manages·​socket·​timeouts·​by·​applying·​the·​concept·​of·​a·​deadline.​71 /​/​·​This·​class·​manages·​socket·​timeouts·​by·​applying·​the·​concept·​of·​a·​deadline.​
73 /​/​·​Some·​asynchronous·​operations·​are·​given·​deadlines·​by·​which·​they·​must·​complete.​72 /​/​·​Some·​asynchronous·​operations·​are·​given·​deadlines·​by·​which·​they·​must·​complete.​
74 /​/​·​Deadlines·​are·​enforced·​by·​two·​"actors"·​that·​persist·​for·​the·​lifetime·​of·​the73 /​/​·​Deadlines·​are·​enforced·​by·​two·​"actors"·​that·​persist·​for·​the·​lifetime·​of·​the
75 /​/​·​session·​object,​·​one·​for·​input·​and·​one·​for·​output:​74 /​/​·​session·​object,​·​one·​for·​input·​and·​one·​for·​output:​
76 /​/​75 /​/​
77 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+·····················​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+76 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+······················​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
78 /​/​··​|················​|·····················​|················​|77 /​/​··​|················​|······················​|················​|
79 /​/​··​|·​check_deadline·​|<-​-​-​+················​|·​check_deadline·​|<-​-​-​+78 /​/​··​|·​check_deadline·​|<-​-​-​-​-​-​-​+·············​|·​check_deadline·​|<-​-​-​-​-​-​-​+
80 /​/​··​|················​|····|·async_wait()​···​|················​|····|·async_wait()​79 /​/​··​|················​|········|·············​|················​|········|
81 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+····|··on·input······​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+····|··on·output80 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+········|·············​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+········|
82 /​/​··············​|·········|··deadline··················​|·········|··deadline81 /​/​···············​|············|··························​|············|
83 /​/​··············​+-​-​-​-​-​-​-​-​-​+····························+-​-​-​-​-​-​-​-​-​+82 /​/​··async_wait()​·|····​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+····async_wait()​·|····+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
83 /​/​···​on·​input····​|····​|·····​lambda·····​|·····​on·​output···​|····​|·····​lambda·····​|
84 /​/​···​deadline····​+-​-​-​>|·······​in·······​|·····​deadline····​+-​-​-​>|·······​in·······​|
85 /​/​····················​|·​check_deadline·​|······················​|·​check_deadline·​|
86 /​/​····················​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+······················​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
84 /​/​87 /​/​
85 /​/​·​If·​either·​deadline·​actor·​determines·​that·​the·​corresponding·​deadline·​has88 /​/​·​If·​either·​deadline·​actor·​determines·​that·​the·​corresponding·​deadline·​has
86 /​/​·​expired,​·​the·​socket·​is·​closed·​and·​any·​outstanding·​operations·​are·​cancelled.​89 /​/​·​expired,​·​the·​socket·​is·​closed·​and·​any·​outstanding·​operations·​are·​cancelled.​
87 /​/​90 /​/​
88 /​/​·​The·​input·​actor·​reads·​messages·​from·​the·​socket,​·​where·​messages·​are·​delimited91 /​/​·​The·​input·​actor·​reads·​messages·​from·​the·​socket,​·​where·​messages·​are·​delimited
89 /​/​·​by·​the·​newline·​character:​92 /​/​·​by·​the·​newline·​character:​
90 /​/​93 /​/​
91 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​+94 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​+
92 /​/​··​|············​|95 /​/​··​|·············​|
93 /​/​··​|·start_read·​|<-​-​-​+96 /​/​··​|··read_line··​|<-​-​-​-​+
94 /​/​··​|············​|····​|97 /​/​··​|·············​|·····​|
95 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​+····​|98 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​+·····​|
96 /​/​··········​|·········​|99 /​/​··········​|···········​|
97 /​/​··​async_-​·​|····​+-​-​-​-​-​-​-​-​-​-​-​-​-​+100 /​/​··​async_-​·​|····​+-​-​-​-​-​-​-​-​-​-​-​-​-​+
98 /​/​···​read_-​·​|····​|·············​|101 /​/​···​read_-​·​|····​|···lambda····​|
99 /​/​··​until()​·​+-​-​-​>|·handle_read·​|102 /​/​··​until()​·​+-​-​-​>|·····in······​|
100 /​/​···············​|·············​|103 /​/​···············​|··read_line··​|
101 /​/​···············​+-​-​-​-​-​-​-​-​-​-​-​-​-​+104 /​/​···············​+-​-​-​-​-​-​-​-​-​-​-​-​-​+
102 /​/​105 /​/​
103 /​/​·​The·​deadline·​for·​receiving·​a·​complete·​message·​is·​30·​seconds.​·​If·​a·​non-​empty106 /​/​·​The·​deadline·​for·​receiving·​a·​complete·​message·​is·​30·​seconds.​·​If·​a·​non-​empty
104 /​/​·​message·​is·​received,​·​it·​is·​delivered·​to·​all·​subscribers.​·​If·​a·​heartbeat·​(a107 /​/​·​message·​is·​received,​·​it·​is·​delivered·​to·​all·​subscribers.​·​If·​a·​heartbeat·​(a
105 /​/​·​message·​that·​consists·​of·​a·​single·​newline·​character)​·​is·​received,​·​a·​heartbeat108 /​/​·​message·​that·​consists·​of·​a·​single·​newline·​character)​·​is·​received,​·​a·​heartbeat
106 /​/​·​is·​enqueued·​for·​the·​client,​·​provided·​there·​are·​no·​other·​messages·​waiting·​to109 /​/​·​is·​enqueued·​for·​the·​client,​·​provided·​there·​are·​no·​other·​messages·​waiting·​to
107 /​/​·​be·​sent.​110 /​/​·​be·​sent.​
108 /​/​111 /​/​
109 /​/​·​The·​output·​actor·​is·​responsible·​for·​sending·​messages·​to·​the·​client:​112 /​/​·​The·​output·​actor·​is·​responsible·​for·​sending·​messages·​to·​the·​client:​
110 /​/​113 /​/​
111 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+114 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
112 /​/​··​|··············​|<-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+115 /​/​··​|················​|<-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
113 /​/​··​|·​await_output·​|······················​|116 /​/​··​|··​await_output··​|······················​|
114 /​/​··​|··············​|<-​-​-​+·················​|117 /​/​··​|················​|<-​-​-​-​-​-​-​+·············​|
115 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+····|·················​|118 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+········|·············​|
116 /​/​······|······|········|·async_wait()​····​|119 /​/​····|············|··········|·············​|
117 /​/​······|······​+-​-​-​-​-​-​-​-​+·················​|120 /​/​····|····async_-​·|··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+····​|
118 /​/​······V·································​|121 /​/​····|·····wait()​·|··|·····lambda·····|····​|
119 /​/​··+-​-​-​-​-​-​-​-​-​-​-​-​-​+···············+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+122 /​/​····|············+-​>|·······in·······|····|
120 /​/​··|·············|·async_write()​·|··············​|123 /​/​····|···············|··await_output··|····​|
121 /​/​··​|·start_write·|-​-​-​-​-​-​-​-​-​-​-​-​-​-​>|·handle_write·​|124 /​/​····​|···············+-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​+····​|
122 /​/​··|·············|···············|··············​|125 /​/​····V·····································​|
123 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​+···············​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+126 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+···············​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
127 /​/​··​|··············​|·​async_write()​·​|····​lambda····​|
128 /​/​··​|··​write_line··​|-​-​-​-​-​-​-​-​-​-​-​-​-​-​>|······​in······​|
129 /​/​··​|··············​|···············​|··​write_line··​|
130 /​/​··​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+···············​+-​-​-​-​-​-​-​-​-​-​-​-​-​-​+
124 /​/​131 /​/​
125 /​/​·​The·​output·​actor·​first·​waits·​for·​an·​output·​message·​to·​be·​enqueued.​·​It·​does132 /​/​·​The·​output·​actor·​first·​waits·​for·​an·​output·​message·​to·​be·​enqueued.​·​It·​does
126 /​/​·​this·​by·​using·​a·​steady_timer·​as·​an·​asynchronous·​condition·​variable.​·​The133 /​/​·​this·​by·​using·​a·​steady_timer·​as·​an·​asynchronous·​condition·​variable.​·​The
127 /​/​·​steady_timer·​will·​be·​signalled·​whenever·​the·​output·​queue·​is·​non-​empty.​134 /​/​·​steady_timer·​will·​be·​signalled·​whenever·​the·​output·​queue·​is·​non-​empty.​
128 /​/​135 /​/​
129 /​/​·​Once·​a·​message·​is·​available,​·​it·​is·​sent·​to·​the·​client.​·​The·​deadline·​for136 /​/​·​Once·​a·​message·​is·​available,​·​it·​is·​sent·​to·​the·​client.​·​The·​deadline·​for
130 /​/​·​sending·​a·​complete·​message·​is·​30·​seconds.​·​After·​the·​message·​is·​successfully137 /​/​·​sending·​a·​complete·​message·​is·​30·​seconds.​·​After·​the·​message·​is·​successfully
131 /​/​·​sent,​·​the·​output·​actor·​again·​waits·​for·​the·​output·​queue·​to·​become·​non-​empty.​138 /​/​·​sent,​·​the·​output·​actor·​again·​waits·​for·​the·​output·​queue·​to·​become·​non-​empty.​
132 /​/​139 /​/​
133 class·​tcp_session140 class·​tcp_session
134 ··​:​·​public·​subscriber,​141 ··​:​·​public·​subscriber,​
135 ····​public·boost:​:​enable_shared_from_th​is<tcp_session>142 ····​public·​std:​:​enable_shared_from_th​is<tcp_session>
136 {143 {
137 public:​144 public:​
138 ··​tcp_session(asio:​:​io_context&·io_context,​·​channel&·​ch)​145 ··​tcp_session(tcp:​:​socket·socket,​·​channel&·​ch)​
139 ····​:​·​channel_(ch)​,​146 ····​:​·​channel_(ch)​,​
140 ······​socket_(io_context)​,​147 ······​socket_(std:​:​move(socket)​)​
141 ······input_deadline_(io_co​ntext)​,​
142 ······non_empty_output_queu​e_(io_context)​,​
143 ······output_deadline_(io_c​ontext)​
144 ··​{148 ··​{
145 ····​input_deadline_.​expires_at(steady_tim​er:​:​time_point:​:​max()​)​;​149 ····​input_deadline_.​expires_at(steady_tim​er:​:​time_point:​:​max()​)​;​
146 ····​output_deadline_.​expires_at(steady_tim​er:​:​time_point:​:​max()​)​;​150 ····​output_deadline_.​expires_at(steady_tim​er:​:​time_point:​:​max()​)​;​
147 151
148 ····​/​/​·​The·​non_empty_output_queu​e_·​steady_timer·​is·​set·​to·​the·​maximum·​time152 ····​/​/​·​The·​non_empty_output_queu​e_·​steady_timer·​is·​set·​to·​the·​maximum·​time
149 ····​/​/​·​point·​whenever·​the·​output·​queue·​is·​empty.​·​This·​ensures·​that·​the·​output153 ····​/​/​·​point·​whenever·​the·​output·​queue·​is·​empty.​·​This·​ensures·​that·​the·​output
150 ····​/​/​·​actor·​stays·​asleep·​until·​a·​message·​is·​put·​into·​the·​queue.​154 ····​/​/​·​actor·​stays·​asleep·​until·​a·​message·​is·​put·​into·​the·​queue.​
151 ····​non_empty_output_queu​e_.​expires_at(steady_tim​er:​:​time_point:​:​max()​)​;​155 ····​non_empty_output_queu​e_.​expires_at(steady_tim​er:​:​time_point:​:​max()​)​;​
152 ··​}156 ··​}
153 157
154 ··​tcp:​:​socket&·​socket()​
155 ··​{
156 ····​return·​socket_;​
157 ··​}
158
159 ··​/​/​·​Called·​by·​the·​server·​object·​to·​initiate·​the·​four·​actors.​158 ··​/​/​·​Called·​by·​the·​server·​object·​to·​initiate·​the·​four·​actors.​
160 ··​void·​start()​159 ··​void·​start()​
161 ··​{160 ··​{
162 ····​channel_.​join(shared_from_this​()​)​;​161 ····​channel_.​join(shared_from_this​()​)​;​
163 162
164 ····start_read()​;​163 ····read_line()​;​
165 164 ····check_deadline(input_​deadline_)​;​
166 ····input_deadline_.​async_wait(
167 ········boost:​:​bind(&tcp_session:​:​check_deadline,​
168 ········shared_from_this()​,​·&input_deadline_)​)​;​
169 165
170 ····​await_output()​;​166 ····​await_output()​;​
171 167 ····check_deadline(output​_deadline_)​;​
172 ····output_deadline_.​async_wait(
173 ········boost:​:​bind(&tcp_session:​:​check_deadline,​
174 ········shared_from_this()​,​·&output_deadline_)​)​;​
175 ··​}168 ··​}
176 169
177 private:​170 private:​
178 ··​void·​stop()​171 ··​void·​stop()​
179 ··​{172 ··​{
180 ····​channel_.​leave(shared_from_thi​s()​)​;​173 ····​channel_.​leave(shared_from_thi​s()​)​;​
181 174
182 ····asio:​:​error_code·​ignored_ec;​175 ····​std:​:​error_code·​ignored_error;​
183 ····​socket_.​close(ignored_ec)​;​176 ····​socket_.​close(ignored_error)​;​
184 ····​input_deadline_.​cancel()​;​177 ····​input_deadline_.​cancel()​;​
185 ····​non_empty_output_queu​e_.​cancel()​;​178 ····​non_empty_output_queu​e_.​cancel()​;​
186 ····​output_deadline_.​cancel()​;​179 ····​output_deadline_.​cancel()​;​
187 ··​}180 ··​}
188 181
189 ··​bool·​stopped()​·​const182 ··​bool·​stopped()​·​const
190 ··​{183 ··​{
191 ····​return·​!socket_.​is_open()​;​184 ····​return·​!socket_.​is_open()​;​
192 ··​}185 ··​}
193 186
194 ··​void·​deliver(const·​std:​:​string&·​msg)​187 ··​void·​deliver(const·​std:​:​string&·​msg)​·override
195 ··​{188 ··​{
196 ····​output_queue_.​push_back(msg·​+·​"\n")​;​189 ····​output_queue_.​push_back(msg·​+·​"\n")​;​
197 190
198 ····​/​/​·​Signal·​that·​the·​output·​queue·​contains·​messages.​·​Modifying·​the·​expiry191 ····​/​/​·​Signal·​that·​the·​output·​queue·​contains·​messages.​·​Modifying·​the·​expiry
199 ····​/​/​·​will·​wake·​the·​output·​actor,​·​if·​it·​is·​waiting·​on·​the·​timer.​192 ····​/​/​·​will·​wake·​the·​output·​actor,​·​if·​it·​is·​waiting·​on·​the·​timer.​
200 ····​non_empty_output_queu​e_.​expires_at(steady_tim​er:​:​time_point:​:​min()​)​;​193 ····​non_empty_output_queu​e_.​expires_at(steady_tim​er:​:​time_point:​:​min()​)​;​
201 ··​}194 ··​}
202 195
203 ··​void·start_read()​196 ··​void·read_line()​
204 ··​{197 ··​{
205 ····​/​/​·​Set·​a·​deadline·​for·​the·​read·​operation.​198 ····​/​/​·​Set·​a·​deadline·​for·​the·​read·​operation.​
206 ····​input_deadline_.​expires_after(asio:​:​chrono:​:​seconds(30)​)​;​199 ····​input_deadline_.​expires_after(std:​:​chrono:​:​seconds(30)​)​;​
207 200
208 ····​/​/​·​Start·​an·​asynchronous·​operation·​to·​read·​a·​newline-​delimited·​message.​201 ····​/​/​·​Start·​an·​asynchronous·​operation·​to·​read·​a·​newline-​delimited·​message.​
202 ····​auto·​self(shared_from_this​()​)​;​
209 ····​asio:​:​async_read_until(sock​et_,​203 ····​asio:​:​async_read_until(sock​et_,​
210 ········​asio:​:​dynamic_buffer(input_​buffer_)​,​·​'\n',​204 ········​asio:​:​dynamic_buffer(input_​buffer_)​,​·​'\n',​
211 ········boost:​:​bind(&tcp_session:​:​handle_read,​·​shared_from_this()​,​205 ········[this,​·self](const·std:​:​error_code&·error,​·​std:​:​size_t·n)​
212 ··········boost:​:​placeholders:​:​_1,​·boost:​:​placeholders:​:​_2)​)​;​
213 ··}
214
215 ··void·handle_read(const·asio:​:​error_code&·ec,​·std:​:​size_t·n)​
216 ··{
217 ····if·(stopped()​)​
218 ······return;​
219
220 ····if·(!ec)​
221 ····{
222 ······/​/​·Extract·the·newline-​delimited·message·from·the·buffer.​
223 ······std:​:​string·msg(input_buffer_.​substr(0,​·n·-​·1)​)​;​
224 ······input_buffer_.​erase(0,​·n)​;​
225
226 ······if·(!msg.​empty()​)​
227 ······{
228 ········channel_.​deliver(msg)​;​
229 ······}
230 ······else
231 ······{
232 ········/​/​·We·received·a·heartbeat·message·from·the·client.​·If·there's·nothing
233 ········/​/​·else·being·sent·or·ready·to·be·sent,​·send·a·heartbeat·right·back.​
234 ········if·(output_queue_.​empty()​)​
235 ········​{206 ········​{
236 ··········​output_queue_.​push_back("\n")​;​207 ··········/​/​·Check·if·the·session·was·stopped·while·the·operation·was·pending.​
237 208 ··········if·(stopped()​)​
238 ··········/​/​·Signal·that·the·output·queue·contains·messages.​·Modifying·the209 ············return;​
239 ··········/​/​·expiry·will·wake·the·output·actor,​·if·it·is·waiting·on·the·timer.​210
240 ··········non_empty_output_queu​e_.​expires_at(steady_tim​er:​:​time_point:​:​min()​)​;​211 ··········​if·(!error)​
241 ········}212 ··········{
242 ······}213 ············/​/​·Extract·the·newline-​delimited·message·from·the·buffer.​
243 214 ············std:​:​string·msg(input_buffer_.​substr(0,​·n·-​·1)​)​;​
244 ······start_read()​;​215 ············input_buffer_.​erase(0,​·n)​;​
245 ····}216
246 ····else217 ············if·(!msg.​empty()​)​
247 ····​{218 ············​{
248 ······stop()​;​219 ··············channel_.​deliver(msg)​;​
249 ····​}220 ············​}
221 ············​else
222 ············​{
223
224 ··············​/​/​·​We·​received·​a·​heartbeat·​message·​from·​the·​client.​·​If·​there's
225 ··············​/​/​·​nothing·​else·​being·​sent·​or·​ready·​to·​be·​sent,​·​send·​a·​heartbeat
226 ··············​/​/​·​right·​back.​
227 ··············​if·​(output_queue_.​empty()​)​
228 ··············​{
229 ················​output_queue_.​push_back("\n")​;​
230
231 ················​/​/​·​Signal·​that·​the·​output·​queue·​contains·​messages.​·​Modifying
232 ················​/​/​·​the·​expiry·​will·​wake·​the·​output·​actor,​·​if·​it·​is·​waiting·​on
233 ················​/​/​·​the·​timer.​
234 ················​non_empty_output_queu​e_.​expires_at(
235 ····················​steady_timer:​:​time_point:​:​min()​)​;​
236 ··············​}
237 ············​}
238
239 ············​read_line()​;​
240 ··········​}
241 ··········​else
242 ··········​{
243 ············​stop()​;​
244 ··········​}
245 ········​})​;​
250 ··​}246 ··​}
251 247
252 ··​void·​await_output()​248 ··​void·​await_output()​
253 ··​{249 ··​{
254 ····if·​(stopped()​)​250 ····auto·self(shared_from_this​()​)​;​
255 ······return;​251 ····non_empty_output_queu​e_.​async_wait(
256 252 ········[this,​·self](const·std:​:​error_code&·/​*error*/​)​
257 ····if·(output_queue_.​empty()​)​253 ········{
258 ····{254 ··········/​/​·Check·if·the·session·was·stopped·while·the·operation·was·pending.​
259 ······/​/​·There·are·no·messages·that·are·ready·to·be·sent.​·The·actor·goes·to255 ··········if·(stopped()​)​
260 ······/​/​·sleep·by·waiting·on·the·non_empty_output_queu​e_·timer.​·When·a·new256 ············return;​
261 ······/​/​·message·is·added,​·the·timer·will·be·modified·and·the·actor·will·wake.​257
262 ······non_empty_output_queu​e_.​expires_at(steady_tim​er:​:​time_point:​:​max()​)​;​258 ··········if·(output_queue_.​empty()​)​
263 ······non_empty_output_queu​e_.​async_wait(259 ··········{
264 ··········boost:​:​bind(&tcp_session:​:​await_output,​·shared_from_this()​)​)​;​260 ············/​/​·There·are·no·messages·that·are·ready·to·be·sent.​·The·actor·goes
265 ····}261 ············/​/​·to·sleep·by·waiting·on·the·non_empty_output_queu​e_·timer.​·When·a
266 ····​else262 ············/​/​·new·message·is·added,​·the·timer·will·be·modified·and·the·actor
267 ····{263 ············/​/​·will·wake.​
268 ······​start_write()​;​264 ············non_empty_output_queu​e_.​expires_at(steady_tim​er:​:​time_point:​:​max()​)​;​
269 ····}265 ············await_output()​;​
266 ··········​}
267 ··········​else
268 ··········​{
269 ············​write_line()​;​
270 ··········​}
271 ········​})​;​
270 ··​}272 ··​}
271 273
272 ··​void·start_write()​274 ··​void·write_line()​
273 ··​{275 ··​{
274 ····​/​/​·​Set·​a·​deadline·​for·​the·​write·​operation.​276 ····​/​/​·​Set·​a·​deadline·​for·​the·​write·​operation.​
275 ····​output_deadline_.​expires_after(asio:​:​chrono:​:​seconds(30)​)​;​277 ····​output_deadline_.​expires_after(std:​:​chrono:​:​seconds(30)​)​;​
276 278
277 ····​/​/​·​Start·​an·​asynchronous·​operation·​to·​send·​a·​message.​279 ····​/​/​·​Start·​an·​asynchronous·​operation·​to·​send·​a·​message.​
280 ····​auto·​self(shared_from_this​()​)​;​
278 ····​asio:​:​async_write(socket_,​281 ····​asio:​:​async_write(socket_,​
279 ········​asio:​:​buffer(output_queue_.​front()​)​,​282 ········​asio:​:​buffer(output_queue_.​front()​)​,​
280 ········boost:​:​bind(&tcp_session:​:​handle_write,​283 ········[this,​·self](const·std:​:​error_code&·error,​·std:​:​size_t·/​*n*/​)​
281 ··········shared_from_this()​,​·boost:​:​placeholders:​:​_1)​)​;​284 ········{
282 ··}285 ··········/​/​·Check·if·the·session·was·stopped·while·the·operation·was·pending.​
283 286 ··········if·(stopped()​)​
284 ··void·handle_write(const·asio:​:​error_code&·ec)​287 ············return;​
285 ··{288
286 ····if·(stopped()​)​289 ··········if·(!error)​
287 ······return;​290 ··········{
288 291 ············output_queue_.​pop_front()​;​
289 ····if·(!ec)​292
290 ····{293 ············await_output()​;​
291 ······output_queue_.​pop_front()​;​294 ··········}
292 295 ··········else
293 ······await_output()​;​296 ··········{
294 ····}297 ············stop()​;​
295 ····else298 ··········}
296 ····{299 ········})​;​
297 ······stop()​;​300 ··}
298 ····}301
299 ··}302 ··void·check_deadline(steady​_timer&·deadline)​
300 303 ··{
301 ··void·check_deadline(steady​_timer*·deadline)​304 ····auto·self(shared_from_this​()​)​;​
302 ··{305 ····deadline.​async_wait(
303 ····​if·​(stopped()​)​306 ········[this,​·self,​·&deadline](const·std:​:​error_code&·/​*error*/​)​
304 ······return;​307 ········{
305 308 ··········/​/​·Check·if·the·session·was·stopped·while·the·operation·was·pending.​
306 ····/​/​·Check·whether·the·deadline·has·passed.​·We·compare·the·deadline·against309 ··········if·(stopped()​)​
307 ····/​/​·the·current·time·since·a·new·asynchronous·operation·may·have·moved·the310 ············​return;​
308 ····/​/​·deadline·before·this·actor·had·a·chance·to·run.​311
309 ····if·(deadline-​>expiry()​·<=·​steady_timer:​:​clock_type:​:​now()​)​312 ··········/​/​·Check·whether·the·deadline·has·passed.​·We·compare·the·deadline
310 ····{313 ··········/​/​·against·the·current·time·since·a·new·asynchronous·operation·may
311 ······​/​/​·The·deadline·has·passed.​·Stop·​the·session.​·The·other·actors·will314 ··········​/​/​·have·moved·the·deadline·before·​this·actor·had·a·chance·to·run.​
312 ······/​/​·terminate·as·​soon·as·possible.​315 ··········if·(deadline.​expiry()​·<=·​steady_timer:​:​clock_type:​:​now()​)​
313 ······stop()​;​316 ··········{
314 ····}317 ············/​/​·The·deadline·has·passed.​·Stop·the·session.​·The·other·actors·will
315 ····​else318 ············/​/​·terminate·as·soon·as·possible.​
316 ····{319 ············stop()​;​
317 ······/​/​·Put·the·actor·back·to·sleep.​320 ··········}
318 ······deadline-​>async_wait(321 ··········else
319 ··········boost:​:​bind(&tcp_session:​:​check_deadline,​322 ··········{
320 ··········shared_from_this()​,​·deadline)​)​;​323 ············/​/​·Put·the·actor·back·to·sleep.​
321 ····}324 ············check_deadline(deadli​ne)​;​
325 ··········​}
326 ········​})​;​
322 ··​}327 ··​}
323 328
324 ··​channel&·​channel_;​329 ··​channel&·​channel_;​
325 ··​tcp:​:​socket·​socket_;​330 ··​tcp:​:​socket·​socket_;​
326 ··​std:​:​string·​input_buffer_;​331 ··​std:​:​string·​input_buffer_;​
327 ··​steady_timer·​input_deadline_;​332 ··​steady_timer·​input_deadline_{socke​t_.​get_executor()​};​
328 ··​std:​:​deque<std:​:​string>·​output_queue_;​333 ··​std:​:​deque<std:​:​string>·​output_queue_;​
329 ··​steady_timer·​non_empty_output_queu​e_;​334 ··​steady_timer·​non_empty_output_queu​e_{socket_.​get_executor()​};​
330 ··​steady_timer·​output_deadline_;​335 ··​steady_timer·​output_deadline_{sock​et_.​get_executor()​};​
331 };​336 };​
332 337
333 typedef·boost:​:​shared_ptr<tcp_sessio​n>·​tcp_session_ptr;​338 typedef·​std:​:​shared_ptr<tcp_sessio​n>·​tcp_session_ptr;​
334 339
335 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​340 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
336 341
337 class·​udp_broadcaster342 class·​udp_broadcaster
338 ··​:​·​public·​subscriber343 ··​:​·​public·​subscriber
339 {344 {
340 public:​345 public:​
341 ··​udp_broadcaster(asio:​:​io_context&·​io_context,​346 ··​udp_broadcaster(asio:​:​io_context&·​io_context,​
342 ······​const·​udp:​:​endpoint&·​broadcast_endpoint)​347 ······​const·​udp:​:​endpoint&·​broadcast_endpoint)​
343 ····​:​·​socket_(io_context)​348 ····​:​·​socket_(io_context)​
344 ··​{349 ··​{
345 ····​socket_.​connect(broadcast_end​point)​;​350 ····​socket_.​connect(broadcast_end​point)​;​
346 ····​socket_.​set_option(udp:​:​socket:​:​broadcast(true)​)​;​351 ····​socket_.​set_option(udp:​:​socket:​:​broadcast(true)​)​;​
347 ··​}352 ··​}
348 353
349 private:​354 private:​
350 ··​void·​deliver(const·​std:​:​string&·​msg)​355 ··​void·​deliver(const·​std:​:​string&·​msg)​
351 ··​{356 ··​{
352 ····asio:​:​error_code·​ignored_ec;​357 ····​std:​:​error_code·​ignored_error;​
353 ····​socket_.​send(asio:​:​buffer(msg)​,​·​0,​·​ignored_ec)​;​358 ····​socket_.​send(asio:​:​buffer(msg)​,​·​0,​·​ignored_error)​;​
354 ··​}359 ··​}
355 360
356 ··​udp:​:​socket·​socket_;​361 ··​udp:​:​socket·​socket_;​
357 };​362 };​
358 363
359 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​364 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
360 365
361 class·​server366 class·​server
362 {367 {
363 public:​368 public:​
364 ··​server(asio:​:​io_context&·​io_context,​369 ··​server(asio:​:​io_context&·​io_context,​
365 ······​const·​tcp:​:​endpoint&·​listen_endpoint,​370 ······​const·​tcp:​:​endpoint&·​listen_endpoint,​
366 ······​const·​udp:​:​endpoint&·​broadcast_endpoint)​371 ······​const·​udp:​:​endpoint&·​broadcast_endpoint)​
367 ····​:​·​io_context_(io_contex​t)​,​372 ····​:​·​io_context_(io_contex​t)​,​
368 ······​acceptor_(io_context,​·​listen_endpoint)​373 ······​acceptor_(io_context,​·​listen_endpoint)​
369 ··​{374 ··​{
370 ····subscriber_ptr·bc(new·udp_broadcaster(io_co​ntext_,​·broadcast_endpoint)​)​;​375 ····​channel_.​join(
371 ····channel_.​join(bc)​;​376 ········std:​:​make_shared<udp_broad​caster>(
377 ··········​io_context_,​·​broadcast_endpoint)​)​;​
372 378
373 ····start_accept()​;​379 ····​accept()​;​
374 ··​}380 ··​}
375 381
376 ··void·start_accept()​382 private:​
377 ··{383 ··void·accept()​
378 ····tcp_session_ptr·new_session(new·tcp_session(io_contex​t_,​·channel_)​)​;​
379
380 ····acceptor_.​async_accept(new_sess​ion-​>socket()​,​
381 ········boost:​:​bind(&server:​:​handle_accept,​
382 ··········this,​·new_session,​·boost:​:​placeholders:​:​_1)​)​;​
383 ··}
384
385 ··void·handle_accept(tcp_ses​sion_ptr·session,​
386 ······const·asio:​:​error_code&·ec)​
387 ··​{384 ··​{
388 ····if·(!ec)​385 ····acceptor_.​async_accept(
389 ····{386 ········[this](const·std:​:​error_code&·error,​·tcp:​:​socket·socket)​
390 ······session-​>start()​;​387 ········{
391 ····}388 ··········if·(!error)​
389 ··········​{
390 ············​std:​:​make_shared<tcp_sessi​on>(std:​:​move(socket)​,​·​channel_)​-​>start()​;​
391 ··········​}
392 392
393 ····start_accept()​;​393 ··········accept()​;​
394 ········​})​;​
394 ··​}395 ··​}
395 396
396 private:​
397 ··​asio:​:​io_context&·​io_context_;​397 ··​asio:​:​io_context&·​io_context_;​
398 ··​tcp:​:​acceptor·​acceptor_;​398 ··​tcp:​:​acceptor·​acceptor_;​
399 ··​channel·​channel_;​399 ··​channel·​channel_;​
400 };​400 };​
401 401
402 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​402 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
403 403
404 int·​main(int·​argc,​·​char*·​argv[])​404 int·​main(int·​argc,​·​char*·​argv[])​
405 {405 {
406 ··​try406 ··​try
407 ··​{407 ··​{
408 ····​using·​namespace·​std;​·​/​/​·​For·​atoi.​408 ····​using·​namespace·​std;​·​/​/​·​For·​atoi.​
409 409
410 ····​if·​(argc·​!=·​4)​410 ····​if·​(argc·​!=·​4)​
411 ····​{411 ····​{
412 ······​std:​:​cerr·​<<·​"Usage:​·​server·​<listen_port>·​<bcast_address>·​<bcast_port>\n";​412 ······​std:​:​cerr·​<<·​"Usage:​·​server·​<listen_port>·​<bcast_address>·​<bcast_port>\n";​
413 ······​return·​1;​413 ······​return·​1;​
414 ····​}414 ····​}
415 415
416 ····​asio:​:​io_context·​io_context;​416 ····​asio:​:​io_context·​io_context;​
417 417
418 ····​tcp:​:​endpoint·​listen_endpoint(tcp:​:​v4()​,​·​atoi(argv[1])​)​;​418 ····​tcp:​:​endpoint·​listen_endpoint(tcp:​:​v4()​,​·​atoi(argv[1])​)​;​
419 419
420 ····​udp:​:​endpoint·​broadcast_endpoint(420 ····​udp:​:​endpoint·​broadcast_endpoint(
421 ········​asio:​:​ip:​:​make_address(argv[2])​,​·​atoi(argv[3])​)​;​421 ········​asio:​:​ip:​:​make_address(argv[2])​,​·​atoi(argv[3])​)​;​
422 422
423 ····​server·​s(io_context,​·​listen_endpoint,​·​broadcast_endpoint)​;​423 ····​server·​s(io_context,​·​listen_endpoint,​·​broadcast_endpoint)​;​
424 424
425 ····​io_context.​run()​;​425 ····​io_context.​run()​;​
426 ··​}426 ··​}
427 ··​catch·​(std:​:​exception&·​e)​427 ··​catch·​(std:​:​exception&·​e)​
428 ··​{428 ··​{
429 ····​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​"\n";​429 ····​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​"\n";​
430 ··​}430 ··​}
431 431
432 ··​return·​0;​432 ··​return·​0;​
433 }433 }