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-​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·​<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:​
101 ··​void·​do_read_header()​
118 ··​{102 ··​{
119 ····if·(!error·&&·read_msg_.​decode_header()​)​103 ····auto·self(shared_from_this​()​)​;​
120 ····{104 ····asio:​:​async_read(socket_,​
121 ······​asio:​:​async_read(socket_,​105 ········​asio:​:​buffer(read_msg_.​data()​,​·chat_message:​:​header_length)​,​
122 ··········asio:​:​buffer(read_msg_.​body()​,​·read_msg_.​body_length()​)​,​106 ········[this,​·self](std:​:​error_code·ec,​·std:​:​size_t·/​*length*/​)​
123 ··········boost:​:​bind(&chat_session:​:​handle_read_body,​·shared_from_this()​,​107 ········{
124 ············asio:​:​placeholders:​:​error)​)​;​108 ··········if·(!ec·&&·read_msg_.​decode_header()​)​
125 ····}109 ··········{
126 ····​else110 ············do_read_body()​;​
127 ····{111 ··········}
128 ······room_.​leave(shared_from_thi​s()​)​;​112 ··········else
129 ····}113 ··········{
114 ············​room_.​leave(shared_from_thi​s()​)​;​
115 ··········​}
116 ········​})​;​
130 ··​}117 ··​}
131 118
132 ··​void·handle_read_body(cons​t·asio:​:​error_code&·error)​119 ··​void·​do_read_body()​
133 ··​{120 ··​{
134 ····if·​(!error)​121 ····auto·self(shared_from_this​()​)​;​
135 ····{122 ····asio:​:​async_read(socket_,​
136 ······​room_.​deliver(read_msg_)​;​123 ········asio:​:​buffer(read_msg_.​body()​,​·read_msg_.​body_length()​)​,​
137 ······asio:​:​async_read(socket_,​124 ········[this,​·self](std:​:​error_code·ec,​·std:​:​size_t·/​*length*/​)​
138 ··········asio:​:​buffer(read_msg_.​data()​,​·chat_message:​:​header_length)​,​125 ········{
139 ··········boost:​:​bind(&chat_session:​:​handle_read_header,​·shared_from_this()​,​126 ··········​if·(!ec)​
140 ············asio:​:​placeholders:​:​error)​)​;​127 ··········{
141 ····}128 ············room_.​deliver(read_msg_)​;​
142 ····​else129 ············do_read_header()​;​
143 ····{130 ··········}
144 ······room_.​leave(shared_from_thi​s()​)​;​131 ··········else
145 ····}132 ··········{
133 ············​room_.​leave(shared_from_thi​s()​)​;​
134 ··········​}
135 ········​})​;​
146 ··​}136 ··​}
147 137
148 ··​void·handle_write(const·asio:​:​error_code&·error)​138 ··​void·​do_write()​
149 ··​{139 ··​{
150 ····if·​(!error)​140 ····auto·self(shared_from_this​()​)​;​
151 ····{141 ····asio:​:​async_write(socket_,​
152 ······​write_msgs_.​pop_front()​;​142 ········asio:​:​buffer(write_msgs_.​front()​.​data()​,​
153 ······if·(!write_msgs_.​empty()​)​143 ··········write_msgs_.​front()​.​length()​)​,​
154 ······{144 ········[this,​·self](std:​:​error_code·ec,​·std:​:​size_t·/​*length*/​)​
155 ········asio:​:​async_write(socket_,​145 ········{
156 ············asio:​:​buffer(write_msgs_.​front()​.​data()​,​146 ··········​if·(!ec)​
157 ··············write_msgs_.​front()​.​length()​)​,​147 ··········{
158 ············boost:​:​bind(&chat_session:​:​handle_write,​·shared_from_this()​,​148 ············write_msgs_.​pop_front()​;​
159 ··············asio:​:​placeholders:​:​error)​)​;​149 ············​if·(!write_msgs_.​empty()​)​
160 ······}150 ············{
161 ····}151 ··············do_write()​;​
162 ····else152 ············}
163 ····{153 ··········}
164 ······room_.​leave(shared_from_thi​s()​)​;​154 ··········else
165 ····}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:​
180 ··​void·​do_accept()​
191 ··​{181 ··​{
192 ····chat_session_ptr·new_session(new·chat_session(io_conte​xt_,​·room_)​)​;​182 ····​acceptor_.​async_accept(
193 ····acceptor_.​async_accept(new_sess​ion-​>socket()​,​183 ········[this](std:​:​error_code·ec,​·tcp:​:​socket·socket)​
194 ········boost:​:​bind(&chat_server:​:​handle_accept,​·this,​·new_session,​184 ········{
195 ··········asio:​:​placeholders:​:​error)​)​;​185 ··········​if·(!ec)​
196 ··}186 ··········{
187 ············​std:​:​make_shared<chat_sess​ion>(std:​:​move(socket)​,​·​room_)​-​>start()​;​
188 ··········​}
197 189
198 ··void·handle_accept(chat_se​ssion_ptr·session,​190 ··········do_accept()​;​
199 ······const·asio:​:​error_code&·error)​191 ········})​;​
200 ··{
201 ····if·(!error)​
202 ····{
203 ······session-​>start()​;​
204 ····}
205
206 ····start_accept()​;​
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 }