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 }