src/​examples/​cpp03/​chat/​chat_client.​cppsrc/​examples/​cpp11/​chat/​chat_client.​cpp
⋮⋮
1 /​/​1 /​/​
2 /​/​·​chat_client.​cpp2 /​/​·​chat_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·​<cstdlib>11 #include·​<cstdlib>
12 #include·​<deque>12 #include·​<deque>
13 #include·​<iostream>13 #include·​<iostream>
14 #include·​<boost/​bind/​bind.​hpp>14 #include·​<thread>
15 #include·​"asio.​hpp"15 #include·​"asio.​hpp"
16 #include·​"chat_message.​hpp"16 #include·​"chat_message.​hpp"
17 17
18 using·​asio:​:​ip:​:​tcp;​18 using·​asio:​:​ip:​:​tcp;​
19 19
20 typedef·​std:​:​deque<chat_message>·​chat_message_queue;​20 typedef·​std:​:​deque<chat_message>·​chat_message_queue;​
21 21
22 class·​chat_client22 class·​chat_client
23 {23 {
24 public:​24 public:​
25 ·​·​chat_client(asio:​:​io_context&·​io_context,​25 ·​·​chat_client(asio:​:​io_context&·​io_context,​
26 ·​·​·​·​·​·​const·​tcp:​:​resolver:​:​results_type&·​endpoints)​26 ·​·​·​·​·​·​const·​tcp:​:​resolver:​:​results_type&·​endpoints)​
27 ·​·​·​·​:​·​io_context_(io_contex​t)​,​27 ·​·​·​·​:​·​io_context_(io_contex​t)​,​
28 ·​·​·​·​·​·​socket_(io_context)​28 ·​·​·​·​·​·​socket_(io_context)​
29 ·​·​{29 ·​·​{
30 ·​·​·​·​asio:​:​async_connect(socket_​,​·​endpoints,​30 ·​·​·​·​do_connect(endpoints)​;​
31 ·​·​·​·​·​·​·​·​boost:​:​bind(&chat_client:​:​handle_connect,​·​this,​
32 ·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​error)​)​;​
33 ·​·​}31 ·​·​}
34 32
35 ·​·​void·​write(const·​chat_message&·​msg)​33 ·​·​void·​write(const·​chat_message&·​msg)​
36 ·​·​{34 ·​·​{
37 ·​·​·​·​asio:​:​post(io_context_,​35 ·​·​·​·​asio:​:​post(io_context_,​
38 ·​·​·​·​·​·​·​·​boost:​:​bind(&chat_client:​:​do_write,​·​this,​·​msg)​)​;​36 ·​·​·​·​·​·​·​·​[this,​·​msg]()​
37 ·​·​·​·​·​·​·​·​{
38 ·​·​·​·​·​·​·​·​·​·​bool·​write_in_progress·​=·​!write_msgs_.​empty()​;​
39 ·​·​·​·​·​·​·​·​·​·​write_msgs_.​push_back(msg)​;​
40 ·​·​·​·​·​·​·​·​·​·​if·​(!write_in_progress)​
41 ·​·​·​·​·​·​·​·​·​·​{
42 ·​·​·​·​·​·​·​·​·​·​·​·​do_write()​;​
43 ·​·​·​·​·​·​·​·​·​·​}
44 ·​·​·​·​·​·​·​·​})​;​
39 ·​·​}45 ·​·​}
40 46
41 ·​·​void·​close()​47 ·​·​void·​close()​
42 ·​·​{48 ·​·​{
43 ·​·​·​·​asio:​:​post(io_context_,​49 ·​·​·​·​asio:​:​post(io_context_,​·​[this]()​·​{·​socket_.​close()​;​·​})​;​
44 ·​·​·​·​·​·​·​·​boost:​:​bind(&chat_client:​:​do_close,​·​this)​)​;​
45 ·​·​}50 ·​·​}
46 51
47 private:​52 private:​
48 53 ·​·​void·​do_connect(const·​tcp:​:​resolver:​:​results_type&·​endpoints)​
49 ·​·​void·​handle_connect(const·​asio:​:​error_code&·​error)​
50 ·​·​{54 ·​·​{
51 ·​·​·​·​if·​(!error)​55 ·​·​·​·​asio:​:​async_connect(socket_​,​·​endpoints,​
52 ·​·​·​·​{56 ·​·​·​·​·​·​·​·​[this](std:​:​error_code·​ec,​·​tcp:​:​endpoint)​
53 ·​·​·​·​·​·​asio:​:​async_read(socket_,​57 ·​·​·​·​·​·​·​·​{
54 ·​·​·​·​·​·​·​·​·​·​asio:​:​buffer(read_msg_.​data()​,​·​chat_message:​:​header_length)​,​58 ·​·​·​·​·​·​·​·​·​·​if·​(!ec)​
55 ·​·​·​·​·​·​·​·​·​·​boost:​:​bind(&chat_client:​:​handle_read_header,​·​this,​59 ·​·​·​·​·​·​·​·​·​·​{
56 ·​·​·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​error)​)​;​60 ·​·​·​·​·​·​·​·​·​·​·​·​do_read_header()​;​
57 ·​·​·​·​}61 ·​·​·​·​·​·​·​·​·​·​}
62 ·​·​·​·​·​·​·​·​})​;​
58 ·​·​}63 ·​·​}
59 64
60 ·​·​void·​handle_read_header(co​nst·​asio:​:​error_code&·​error)​65 ·​·​void·​do_read_header()​
61 ·​·​{66 ·​·​{
62 ·​·​·​·​if·​(!error·​&&·​read_msg_.​decode_header()​)​67 ·​·​·​·​asio:​:​async_read(socket_,​
63 ·​·​·​·​{68 ·​·​·​·​·​·​·​·​asio:​:​buffer(read_msg_.​data()​,​·​chat_message:​:​header_length)​,​
64 ·​·​·​·​·​·​asio:​:​async_read(socket_,​69 ·​·​·​·​·​·​·​·​[this](std:​:​error_code·​ec,​·​std:​:​size_t·​/​*length*/​)​
65 ·​·​·​·​·​·​·​·​·​·​asio:​:​buffer(read_msg_.​body()​,​·​read_msg_.​body_length()​)​,​70 ·​·​·​·​·​·​·​·​{
66 ·​·​·​·​·​·​·​·​·​·​boost:​:​bind(&chat_client:​:​handle_read_body,​·​this,​71 ·​·​·​·​·​·​·​·​·​·​if·​(!ec·​&&·​read_msg_.​decode_header()​)​
67 ·​·​·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​error)​)​;​72 ·​·​·​·​·​·​·​·​·​·​{
68 ·​·​·​·​}73 ·​·​·​·​·​·​·​·​·​·​·​·​do_read_body()​;​
69 ·​·​·​·​else74 ·​·​·​·​·​·​·​·​·​·​}
70 ·​·​·​·​{75 ·​·​·​·​·​·​·​·​·​·​else
71 ·​·​·​·​·​·​do_close()​;​76 ·​·​·​·​·​·​·​·​·​·​{
72 ·​·​·​·​}77 ·​·​·​·​·​·​·​·​·​·​·​·​socket_.​close()​;​
78 ·​·​·​·​·​·​·​·​·​·​}
79 ·​·​·​·​·​·​·​·​})​;​
73 ·​·​}80 ·​·​}
74 81
75 ·​·​void·​handle_read_body(cons​t·​asio:​:​error_code&·​error)​82 ·​·​void·​do_read_body()​
76 ·​·​{83 ·​·​{
77 ·​·​·​·​if·​(!error)​84 ·​·​·​·​asio:​:​async_read(socket_,​
78 ·​·​·​·​{85 ·​·​·​·​·​·​·​·​asio:​:​buffer(read_msg_.​body()​,​·​read_msg_.​body_length()​)​,​
79 ·​·​·​·​·​·​std:​:​cout.​write(read_msg_.​body()​,​·​read_msg_.​body_length()​)​;​86 ·​·​·​·​·​·​·​·​[this](std:​:​error_code·​ec,​·​std:​:​size_t·​/​*length*/​)​
80 ·​·​·​·​·​·​std:​:​cout·​<<·​"\n";​87 ·​·​·​·​·​·​·​·​{
81 ·​·​·​·​·​·​asio:​:​async_read(socket_,​88 ·​·​·​·​·​·​·​·​·​·​if·​(!ec)​
82 ·​·​·​·​·​·​·​·​·​·​asio:​:​buffer(read_msg_.​data()​,​·​chat_message:​:​header_length)​,​89 ·​·​·​·​·​·​·​·​·​·​{
83 ·​·​·​·​·​·​·​·​·​·​boost:​:​bind(&chat_client:​:​handle_read_header,​·​this,​90 ·​·​·​·​·​·​·​·​·​·​·​·​std:​:​cout.​write(read_msg_.​body()​,​·​read_msg_.​body_length()​)​;​
84 ·​·​·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​error)​)​;​91 ·​·​·​·​·​·​·​·​·​·​·​·​std:​:​cout·​<<·​"\n";​
85 ·​·​·​·​}92 ·​·​·​·​·​·​·​·​·​·​·​·​do_read_header()​;​
86 ·​·​·​·​else93 ·​·​·​·​·​·​·​·​·​·​}
87 ·​·​·​·​{94 ·​·​·​·​·​·​·​·​·​·​else
88 ·​·​·​·​·​·​do_close()​;​95 ·​·​·​·​·​·​·​·​·​·​{
89 ·​·​·​·​}96 ·​·​·​·​·​·​·​·​·​·​·​·​socket_.​close()​;​
97 ·​·​·​·​·​·​·​·​·​·​}
98 ·​·​·​·​·​·​·​·​})​;​
90 ·​·​}99 ·​·​}
91 100
92 ·​·​void·​do_write(chat_message​·​msg)​101 ·​·​void·​do_write()​
93 ·​·​{102 ·​·​{
94 ·​·​·​·​bool·​write_in_progress·​=·​!write_msgs_.​empty()​;​103 ·​·​·​·​asio:​:​async_write(socket_,​
95 ·​·​·​·​write_msgs_.​push_back(msg)​;​104 ·​·​·​·​·​·​·​·​asio:​:​buffer(write_msgs_.​front()​.​data()​,​
96 ·​·​·​·​if·​(!write_in_progress)​105 ·​·​·​·​·​·​·​·​·​·​write_msgs_.​front()​.​length()​)​,​
97 ·​·​·​·​{106 ·​·​·​·​·​·​·​·​[this](std:​:​error_code·​ec,​·​std:​:​size_t·​/​*length*/​)​
98 ·​·​·​·​·​·​asio:​:​async_write(socket_,​107 ·​·​·​·​·​·​·​·​{
99 ·​·​·​·​·​·​·​·​·​·​asio:​:​buffer(write_msgs_.​front()​.​data()​,​108 ·​·​·​·​·​·​·​·​·​·​if·​(!ec)​
100 ·​·​·​·​·​·​·​·​·​·​·​·​write_msgs_.​front()​.​length()​)​,​109 ·​·​·​·​·​·​·​·​·​·​{
101 ·​·​·​·​·​·​·​·​·​·​boost:​:​bind(&chat_client:​:​handle_write,​·​this,​110 ·​·​·​·​·​·​·​·​·​·​·​·​write_msgs_.​pop_front()​;​
102 ·​·​·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​error)​)​;​111 ·​·​·​·​·​·​·​·​·​·​·​·​if·​(!write_msgs_.​empty()​)​
103 ·​·​·​·​}112 ·​·​·​·​·​·​·​·​·​·​·​·​{
113 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​do_write()​;​
114 ·​·​·​·​·​·​·​·​·​·​·​·​}
115 ·​·​·​·​·​·​·​·​·​·​}
116 ·​·​·​·​·​·​·​·​·​·​else
117 ·​·​·​·​·​·​·​·​·​·​{
118 ·​·​·​·​·​·​·​·​·​·​·​·​socket_.​close()​;​
119 ·​·​·​·​·​·​·​·​·​·​}
120 ·​·​·​·​·​·​·​·​})​;​
104 ·​·​}121 ·​·​}
105 122
106 ·​·​void·​handle_write(const·​asio:​:​error_code&·​error)​
107 ·​·​{
108 ·​·​·​·​if·​(!error)​
109 ·​·​·​·​{
110 ·​·​·​·​·​·​write_msgs_.​pop_front()​;​
111 ·​·​·​·​·​·​if·​(!write_msgs_.​empty()​)​
112 ·​·​·​·​·​·​{
113 ·​·​·​·​·​·​·​·​asio:​:​async_write(socket_,​
114 ·​·​·​·​·​·​·​·​·​·​·​·​asio:​:​buffer(write_msgs_.​front()​.​data()​,​
115 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​write_msgs_.​front()​.​length()​)​,​
116 ·​·​·​·​·​·​·​·​·​·​·​·​boost:​:​bind(&chat_client:​:​handle_write,​·​this,​
117 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​asio:​:​placeholders:​:​error)​)​;​
118 ·​·​·​·​·​·​}
119 ·​·​·​·​}
120 ·​·​·​·​else
121 ·​·​·​·​{
122 ·​·​·​·​·​·​do_close()​;​
123 ·​·​·​·​}
124 ·​·​}
125
126 ·​·​void·​do_close()​
127 ·​·​{
128 ·​·​·​·​socket_.​close()​;​
129 ·​·​}
130
131 private:​123 private:​
132 ·​·​asio:​:​io_context&·​io_context_;​124 ·​·​asio:​:​io_context&·​io_context_;​
133 ·​·​tcp:​:​socket·​socket_;​125 ·​·​tcp:​:​socket·​socket_;​
134 ·​·​chat_message·​read_msg_;​126 ·​·​chat_message·​read_msg_;​
135 ·​·​chat_message_queue·​write_msgs_;​127 ·​·​chat_message_queue·​write_msgs_;​
136 };​128 };​
137 129
138 int·​main(int·​argc,​·​char*·​argv[])​130 int·​main(int·​argc,​·​char*·​argv[])​
139 {131 {
140 ·​·​try132 ·​·​try
141 ·​·​{133 ·​·​{
142 ·​·​·​·​if·​(argc·​!=·​3)​134 ·​·​·​·​if·​(argc·​!=·​3)​
143 ·​·​·​·​{135 ·​·​·​·​{
144 ·​·​·​·​·​·​std:​:​cerr·​<<·​"Usage:​·​chat_client·​<host>·​<port>\n";​136 ·​·​·​·​·​·​std:​:​cerr·​<<·​"Usage:​·​chat_client·​<host>·​<port>\n";​
145 ·​·​·​·​·​·​return·​1;​137 ·​·​·​·​·​·​return·​1;​
146 ·​·​·​·​}138 ·​·​·​·​}
147 139
148 ·​·​·​·​asio:​:​io_context·​io_context;​140 ·​·​·​·​asio:​:​io_context·​io_context;​
149 141
150 ·​·​·​·​tcp:​:​resolver·​resolver(io_context)​;​142 ·​·​·​·​tcp:​:​resolver·​resolver(io_context)​;​
151 ·​·​·​·​tcp:​:​resolver:​:​results_type·​endpoints·​=·​resolver.​resolve(argv[1],​·​argv[2])​;​143 ·​·​·​·​auto·​endpoints·​=·​resolver.​resolve(argv[1],​·​argv[2])​;​
152
153 ·​·​·​·​chat_client·​c(io_context,​·​endpoints)​;​144 ·​·​·​·​chat_client·​c(io_context,​·​endpoints)​;​
154 145
155 ·​·​·​·​asio:​:​thread·​t(boost:​:​bind(&asio:​:​io_context:​:​run,​·​&io_context)​)​;​146 ·​·​·​·​std:​:​thread·​t([&io_context]()​{·​io_context.​run()​;​·​})​;​
156 147
157 ·​·​·​·​char·​line[chat_message:​:​max_body_length·​+·​1];​148 ·​·​·​·​char·​line[chat_message:​:​max_body_length·​+·​1];​
158 ·​·​·​·​while·​(std:​:​cin.​getline(line,​·​chat_message:​:​max_body_length·​+·​1)​)​149 ·​·​·​·​while·​(std:​:​cin.​getline(line,​·​chat_message:​:​max_body_length·​+·​1)​)​
159 ·​·​·​·​{150 ·​·​·​·​{
160 ·​·​·​·​·​·​using·​namespace·​std;​·​/​/​·​For·​strlen·​and·​memcpy.​
161 ·​·​·​·​·​·​chat_message·​msg;​151 ·​·​·​·​·​·​chat_message·​msg;​
162 ·​·​·​·​·​·​msg.​body_length(strlen(li​ne)​)​;​152 ·​·​·​·​·​·​msg.​body_length(std:​:​strlen(line)​)​;​
163 ·​·​·​·​·​·​memcpy(msg.​body()​,​·​line,​·​msg.​body_length()​)​;​153 ·​·​·​·​·​·​std:​:​memcpy(msg.​body()​,​·​line,​·​msg.​body_length()​)​;​
164 ·​·​·​·​·​·​msg.​encode_header()​;​154 ·​·​·​·​·​·​msg.​encode_header()​;​
165 ·​·​·​·​·​·​c.​write(msg)​;​155 ·​·​·​·​·​·​c.​write(msg)​;​
166 ·​·​·​·​}156 ·​·​·​·​}
167 157
168 ·​·​·​·​c.​close()​;​158 ·​·​·​·​c.​close()​;​
169 ·​·​·​·​t.​join()​;​159 ·​·​·​·​t.​join()​;​
170 ·​·​}160 ·​·​}
171 ·​·​catch·​(std:​:​exception&·​e)​161 ·​·​catch·​(std:​:​exception&·​e)​
172 ·​·​{162 ·​·​{
173 ·​·​·​·​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​"\n";​163 ·​·​·​·​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​"\n";​
174 ·​·​}164 ·​·​}
175 165
176 ·​·​return·​0;​166 ·​·​return·​0;​
177 }167 }