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