src/​examples/​cpp03/​chat/​chat_server.​cppsrc/​examples/​cpp11/​chat/​chat_server.​cpp
1 /​/​1 /​/​
2 /​/​·​chat_server.​cpp2 /​/​·​chat_server.​cpp
3 /​/​·​~~~~~~~~~~~~~~~3 /​/​·​~~~~~~~~~~~~~~~
4 /​/​4 /​/​
5 /​/​·​Copyright·​(c)​·​2003-​2018·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​5 /​/​·​Copyright·​(c)​·​2003-​2018·​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>
12 #include·​<cstdlib>11 #include·​<cstdlib>
13 #include·​<deque>12 #include·​<deque>
14 #include·​<iostream>13 #include·​<iostream>
15 #include·​<list>14 #include·​<list>
15 #include·​<memory>
16 #include·​<set>16 #include·​<set>
17 #include·​<boost/​bind.​hpp>17 #include·​<utility>
18 #include·<boost/​shared_ptr.​hpp>
19 #include·<boost/​enable_shared_from_th​is.​hpp>
20 #include·​"asio.​hpp"18 #include·​"asio.​hpp"
21 #include·​"chat_message.​hpp"19 #include·​"chat_message.​hpp"
22 20
23 using·​asio:​:​ip:​:​tcp;​21 using·​asio:​:​ip:​:​tcp;​
24 22
25 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​23 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
26 24
27 typedef·​std:​:​deque<chat_message>·​chat_message_queue;​25 typedef·​std:​:​deque<chat_message>·​chat_message_queue;​
28 26
29 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​27 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
30 28
31 class·​chat_participant29 class·​chat_participant
32 {30 {
33 public:​31 public:​
34 ··​virtual·​~chat_participant()​·​{}32 ··​virtual·​~chat_participant()​·​{}
35 ··​virtual·​void·​deliver(const·​chat_message&·​msg)​·​=·​0;​33 ··​virtual·​void·​deliver(const·​chat_message&·​msg)​·​=·​0;​
36 };​34 };​
37 35
38 typedef·boost:​:​shared_ptr<chat_parti​cipant>·​chat_participant_ptr;​36 typedef·​std:​:​shared_ptr<chat_parti​cipant>·​chat_participant_ptr;​
39 37
40 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​38 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
41 39
42 class·​chat_room40 class·​chat_room
43 {41 {
44 public:​42 public:​
45 ··​void·​join(chat_participant​_ptr·​participant)​43 ··​void·​join(chat_participant​_ptr·​participant)​
46 ··​{44 ··​{
47 ····​participants_.​insert(participant)​;​45 ····​participants_.​insert(participant)​;​
48 ····std:​:​for_each(recent_msgs_​.​begin()​,​·​recent_msgs_.​end()​,​46 ····​for·(auto·msg:​·​recent_msgs_)​
49 ········boost:​:​bind(&chat_participan​t:​:​deliver,​·participant,​·_1)​)​;​47 ······​participant-​>deliver(msg)​;​
50 ··​}48 ··​}
51 49
52 ··​void·​leave(chat_participan​t_ptr·​participant)​50 ··​void·​leave(chat_participan​t_ptr·​participant)​
53 ··​{51 ··​{
54 ····​participants_.​erase(participant)​;​52 ····​participants_.​erase(participant)​;​
55 ··​}53 ··​}
56 54
57 ··​void·​deliver(const·​chat_message&·​msg)​55 ··​void·​deliver(const·​chat_message&·​msg)​
58 ··​{56 ··​{
59 ····​recent_msgs_.​push_back(msg)​;​57 ····​recent_msgs_.​push_back(msg)​;​
60 ····​while·​(recent_msgs_.​size()​·​>·​max_recent_msgs)​58 ····​while·​(recent_msgs_.​size()​·​>·​max_recent_msgs)​
61 ······​recent_msgs_.​pop_front()​;​59 ······​recent_msgs_.​pop_front()​;​
62 60
63 ····std:​:​for_each(participants​_.​begin()​,​·​participants_.​end()​,​61 ····​for·(auto·participant:​·​participants_)​
64 ········boost:​:​bind(&chat_participan​t:​:​deliver,​·_1,​·boost:​:​ref(msg)​)​)​;​62 ······​participant-​>deliver(msg)​;​
65 ··​}63 ··​}
66 64
67 private:​65 private:​
68 ··​std:​:​set<chat_participant_​ptr>·​participants_;​66 ··​std:​:​set<chat_participant_​ptr>·​participants_;​
69 ··​enum·​{·​max_recent_msgs·​=·​100·​};​67 ··​enum·​{·​max_recent_msgs·​=·​100·​};​
70 ··​chat_message_queue·​recent_msgs_;​68 ··​chat_message_queue·​recent_msgs_;​
71 };​69 };​
72 70
73 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​71 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
74 72
75 class·​chat_session73 class·​chat_session
76 ··​:​·​public·​chat_participant,​74 ··​:​·​public·​chat_participant,​
77 ····​public·boost:​:​enable_shared_from_th​is<chat_session>75 ····​public·​std:​:​enable_shared_from_th​is<chat_session>
78 {76 {
79 public:​77 public:​
80 ··​chat_session(asio:​:​io_context&·io_context,​·​chat_room&·​room)​78 ··​chat_session(tcp:​:​socket·socket,​·​chat_room&·​room)​
81 ····​:​·​socket_(io_context)​,​79 ····​:​·​socket_(std:​:​move(socket)​)​,​
82 ······​room_(room)​80 ······​room_(room)​
83 ··​{81 ··​{
84 ··​}82 ··​}
85 83
86 ··​tcp:​:​socket&·​socket()​
87 ··​{
88 ····​return·​socket_;​
89 ··​}
90
91 ··​void·​start()​84 ··​void·​start()​
92 ··​{85 ··​{
93 ····​room_.​join(shared_from_this​()​)​;​86 ····​room_.​join(shared_from_this​()​)​;​
94 ····asio:​:​async_read(socket_,​87 ····do_read_header()​;​
95 ········asio:​:​buffer(read_msg_.​data()​,​·chat_message:​:​header_length)​,​
96 ········boost:​:​bind(
97 ··········&chat_session:​:​handle_read_header,​·shared_from_this()​,​
98 ··········asio:​:​placeholders:​:​error)​)​;​
99 ··​}88 ··​}
100 89
101 ··​void·​deliver(const·​chat_message&·​msg)​90 ··​void·​deliver(const·​chat_message&·​msg)​
102 ··​{91 ··​{
103 ····​bool·​write_in_progress·​=·​!write_msgs_.​empty()​;​92 ····​bool·​write_in_progress·​=·​!write_msgs_.​empty()​;​
104 ····​write_msgs_.​push_back(msg)​;​93 ····​write_msgs_.​push_back(msg)​;​
105 ····​if·​(!write_in_progress)​94 ····​if·​(!write_in_progress)​
106 ····​{95 ····​{
107 ······asio:​:​async_write(socket_,​96 ······do_write()​;​
108 ··········asio:​:​buffer(write_msgs_.​front()​.​data()​,​
109 ············write_msgs_.​front()​.​length()​)​,​
110 ··········boost:​:​bind(&chat_session:​:​handle_write,​·shared_from_this()​,​
111 ············asio:​:​placeholders:​:​error)​)​;​
112 ····​}97 ····​}
113 ··​}98 ··​}
114 99
115 ··void·handle_read_header(co​nst·asio:​:​error_code&·error)​100 private:​
116 ··{101 ··void·do_read_header()​
117 ····if·(!error·&&·read_msg_.​decode_header()​)​
118 ····{
119 ······asio:​:​async_read(socket_,​
120 ··········asio:​:​buffer(read_msg_.​body()​,​·read_msg_.​body_length()​)​,​
121 ··········boost:​:​bind(&chat_session:​:​handle_read_body,​·shared_from_this()​,​
122 ············asio:​:​placeholders:​:​error)​)​;​
123 ····}
124 ····else
125 ····{
126 ······room_.​leave(shared_from_thi​s()​)​;​
127 ····}
128 ··}
129
130 ··void·handle_read_body(cons​t·asio:​:​error_code&·error)​
131 ··​{102 ··​{
132 ····if·​(!error)​103 ····auto·self(shared_from_this​()​)​;​
133 ····{104 ····asio:​:​async_read(socket_,​
134 ······​room_.​deliver(read_msg_)​;​105 ········asio:​:​buffer(read_msg_.​data()​,​·chat_message:​:​header_length)​,​
135 ······asio:​:​async_read(socket_,​106 ········[this,​·self](std:​:​error_code·ec,​·std:​:​size_t·/​*length*/​)​
136 ··········asio:​:​buffer(read_msg_.​data()​,​·chat_message:​:​header_length)​,​107 ········{
137 ··········boost:​:​bind(&chat_session:​:​handle_read_header,​·shared_from_this()​,​108 ··········​if·(!ec·&&·read_msg_.​decode_header()​)​
138 ············asio:​:​placeholders:​:​error)​)​;​109 ··········{
139 ····}110 ············do_read_body()​;​
140 ····else111 ··········}
141 ····{112 ··········else
142 ······room_.​leave(shared_from_thi​s()​)​;​113 ··········{
143 ····}114 ············room_.​leave(shared_from_thi​s()​)​;​
115 ··········​}
116 ········​})​;​
144 ··​}117 ··​}
145 118
146 ··​void·handle_write(const·asio:​:​error_code&·error)​119 ··​void·​do_read_body()​
147 ··​{120 ··​{
148 ····if·​(!error)​121 ····auto·self(shared_from_this​()​)​;​
149 ····{122 ····asio:​:​async_read(socket_,​
150 ······write_msgs_.​pop_front()​;​123 ········asio:​:​buffer(read_msg_.​body()​,​·read_msg_.​body_length()​)​,​
151 ······​if·(!write_msgs_.​empty()​)​124 ········[this,​·self](std:​:​error_code·ec,​·std:​:​size_t·/​*length*/​)​
152 ······​{125 ········​{
153 ········asio:​:​async_write(socket_,​126 ··········if·(!ec)​
154 ············asio:​:​buffer(write_msgs_.​front()​.​data()​,​127 ··········{
155 ··············write_msgs_.​front()​.​length()​)​,​128 ············​room_.​deliver(read_msg_)​;​
156 ············boost:​:​bind(&chat_session:​:​handle_write,​·shared_from_this()​,​129 ············​do_read_header()​;​
157 ··············asio:​:​placeholders:​:​error)​)​;​130 ··········}
158 ······}131 ··········else
159 ····}132 ··········{
160 ····​else133 ············room_.​leave(shared_from_thi​s()​)​;​
161 ····{134 ··········}
162 ······room_.​leave(shared_from_thi​s()​)​;​135 ········})​;​
163 ····​}136 ··​}
137
138 ··​void·​do_write()​
139 ··​{
140 ····​auto·​self(shared_from_this​()​)​;​
141 ····​asio:​:​async_write(socket_,​
142 ········​asio:​:​buffer(write_msgs_.​front()​.​data()​,​
143 ··········​write_msgs_.​front()​.​length()​)​,​
144 ········​[this,​·​self](std:​:​error_code·​ec,​·​std:​:​size_t·​/​*length*/​)​
145 ········​{
146 ··········​if·​(!ec)​
147 ··········​{
148 ············​write_msgs_.​pop_front()​;​
149 ············​if·​(!write_msgs_.​empty()​)​
150 ············​{
151 ··············​do_write()​;​
152 ············​}
153 ··········​}
154 ··········​else
155 ··········​{
156 ············​room_.​leave(shared_from_thi​s()​)​;​
157 ··········​}
158 ········​})​;​
164 ··​}159 ··​}
165 160
166 private:​
167 ··​tcp:​:​socket·​socket_;​161 ··​tcp:​:​socket·​socket_;​
168 ··​chat_room&·​room_;​162 ··​chat_room&·​room_;​
169 ··​chat_message·​read_msg_;​163 ··​chat_message·​read_msg_;​
170 ··​chat_message_queue·​write_msgs_;​164 ··​chat_message_queue·​write_msgs_;​
171 };​165 };​
172 166
173 typedef·​boost:​:​shared_ptr<chat_sessi​on>·​chat_session_ptr;​
174
175 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​167 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
176 168
177 class·​chat_server169 class·​chat_server
178 {170 {
179 public:​171 public:​
180 ··​chat_server(asio:​:​io_context&·​io_context,​172 ··​chat_server(asio:​:​io_context&·​io_context,​
181 ······​const·​tcp:​:​endpoint&·​endpoint)​173 ······​const·​tcp:​:​endpoint&·​endpoint)​
182 ····​:​·io_context_(io_contex​t)​,​174 ····​:​·acceptor_(io_context,​·endpoint)​
183 ······acceptor_(io_context,​·endpoint)​
184 ··​{175 ··​{
185 ····start_accept()​;​176 ····do_accept()​;​
186 ··​}177 ··​}
187 178
188 ··void·start_accept()​179 private:​
189 ··{180 ··void·do_accept()​
190 ····chat_session_ptr·new_session(new·chat_session(io_conte​xt_,​·room_)​)​;​
191 ····acceptor_.​async_accept(new_sess​ion-​>socket()​,​
192 ········boost:​:​bind(&chat_server:​:​handle_accept,​·this,​·new_session,​
193 ··········asio:​:​placeholders:​:​error)​)​;​
194 ··}
195
196 ··void·handle_accept(chat_se​ssion_ptr·session,​
197 ······const·asio:​:​error_code&·error)​
198 ··​{181 ··​{
199 ····if·(!error)​182 ····acceptor_.​async_accept(
200 ····{183 ········[this](std:​:​error_code·ec,​·tcp:​:​socket·socket)​
201 ······session-​>start()​;​184 ········{
202 ····}185 ··········if·(!ec)​
186 ··········​{
187 ············​std:​:​make_shared<chat_sess​ion>(std:​:​move(socket)​,​·​room_)​-​>start()​;​
188 ··········​}
203 189
204 ····start_accept()​;​190 ··········do_accept()​;​
191 ········​})​;​
205 ··​}192 ··​}
206 193
207 private:​
208 ··​asio:​:​io_context&·​io_context_;​
209 ··​tcp:​:​acceptor·​acceptor_;​194 ··​tcp:​:​acceptor·​acceptor_;​
210 ··​chat_room·​room_;​195 ··​chat_room·​room_;​
211 };​196 };​
212 197
213 typedef·​boost:​:​shared_ptr<chat_serve​r>·​chat_server_ptr;​
214 typedef·​std:​:​list<chat_server_ptr>​·​chat_server_list;​
215
216 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​198 /​/​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​-​
217 199
218 int·​main(int·​argc,​·​char*·​argv[])​200 int·​main(int·​argc,​·​char*·​argv[])​
219 {201 {
220 ··​try202 ··​try
221 ··​{203 ··​{
222 ····​if·​(argc·​<·​2)​204 ····​if·​(argc·​<·​2)​
223 ····​{205 ····​{
224 ······​std:​:​cerr·​<<·​"Usage:​·​chat_server·​<port>·​[<port>·​.​.​.​]\n";​206 ······​std:​:​cerr·​<<·​"Usage:​·​chat_server·​<port>·​[<port>·​.​.​.​]\n";​
225 ······​return·​1;​207 ······​return·​1;​
226 ····​}208 ····​}
227 209
228 ····​asio:​:​io_context·​io_context;​210 ····​asio:​:​io_context·​io_context;​
229 211
230 ····​chat_server_list·​servers;​212 ····std:​:​list<chat_server>·​servers;​
231 ····​for·​(int·​i·​=·​1;​·​i·​<·​argc;​·​++i)​213 ····​for·​(int·​i·​=·​1;​·​i·​<·​argc;​·​++i)​
232 ····​{214 ····​{
233 ······using·​namespace·​std;​·/​/​·For·atoi.​215 ······tcp:​:​endpoint·endpoint(tcp:​:​v4()​,​·​std:​:​atoi(argv[i])​)​;​
234 ······tcp:​:​endpoint·endpoint(tcp:​:​v4()​,​·atoi(argv[i])​)​;​216 ······servers.​emplace_back(io_conte​xt,​·endpoint)​;​
235 ······chat_server_ptr·server(new·chat_server(io_contex​t,​·endpoint)​)​;​
236 ······servers.​push_back(server)​;​
237 ····​}217 ····​}
238 218
239 ····​io_context.​run()​;​219 ····​io_context.​run()​;​
240 ··​}220 ··​}
241 ··​catch·​(std:​:​exception&·​e)​221 ··​catch·​(std:​:​exception&·​e)​
242 ··​{222 ··​{
243 ····​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​"\n";​223 ····​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​"\n";​
244 ··​}224 ··​}
245 225
246 ··​return·​0;​226 ··​return·​0;​
247 }227 }