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-​2020·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​5 /​/​·​Copyright·​(c)​·​2003-​2020·​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 ··{
51 ····if·(!error)​
52 ····{
53 ······asio:​:​async_read(socket_,​
54 ··········asio:​:​buffer(read_msg_.​data()​,​·chat_message:​:​header_length)​,​
55 ··········boost:​:​bind(&chat_client:​:​handle_read_header,​·this,​
56 ············asio:​:​placeholders:​:​error)​)​;​
57 ····}
58 ··}
59
60 ··void·handle_read_header(co​nst·asio:​:​error_code&·error)​
61 ··{
62 ····if·(!error·&&·read_msg_.​decode_header()​)​
63 ····{
64 ······asio:​:​async_read(socket_,​
65 ··········asio:​:​buffer(read_msg_.​body()​,​·read_msg_.​body_length()​)​,​
66 ··········boost:​:​bind(&chat_client:​:​handle_read_body,​·this,​
67 ············asio:​:​placeholders:​:​error)​)​;​
68 ····}
69 ····else
70 ····{
71 ······do_close()​;​
72 ····}
73 ··}
74
75 ··void·handle_read_body(cons​t·asio:​:​error_code&·error)​
76 ··{
77 ····if·(!error)​
78 ····{
79 ······std:​:​cout.​write(read_msg_.​body()​,​·read_msg_.​body_length()​)​;​
80 ······std:​:​cout·<<·"\n";​
81 ······asio:​:​async_read(socket_,​
82 ··········asio:​:​buffer(read_msg_.​data()​,​·chat_message:​:​header_length)​,​
83 ··········boost:​:​bind(&chat_client:​:​handle_read_header,​·this,​
84 ············asio:​:​placeholders:​:​error)​)​;​
85 ····}
86 ····else
87 ····{
88 ······do_close()​;​
89 ····}
90 ··}
91
92 ··void·do_write(chat_message​·msg)​
93 ··{
94 ····bool·write_in_progress·=·!write_msgs_.​empty()​;​
95 ····write_msgs_.​push_back(msg)​;​
96 ····if·(!write_in_progress)​
97 ····{
98 ······asio:​:​async_write(socket_,​
99 ··········asio:​:​buffer(write_msgs_.​front()​.​data()​,​
100 ············write_msgs_.​front()​.​length()​)​,​
101 ··········boost:​:​bind(&chat_client:​:​handle_write,​·this,​
102 ············asio:​:​placeholders:​:​error)​)​;​
103 ····}
104 ··}
105
106 ··void·handle_write(const·asio:​:​error_code&·error)​
107 ··​{54 ··​{
108 ····​if·(!error)​55 ····asio:​:​async_connect(socket_​,​·endpoints,​
109 ····{56 ········[this](std:​:​error_code·ec,​·tcp:​:​endpoint)​
110 ······write_msgs_.​pop_front()​;​57 ········{
111 ······if·(!write_msgs_.​empty()​)​58 ··········if·(!ec)​
112 ······​{59 ··········​{
113 ········asio:​:​async_write(socket_,​60 ············do_read_header()​;​
114 ············asio:​:​buffer(write_msgs_.​front()​.​data()​,​61 ··········}
115 ··············write_msgs_.​front()​.​length()​)​,​62 ········})​;​
116 ············boost:​:​bind(&chat_client:​:​handle_write,​·this,​63 ··}
117 ··············asio:​:​placeholders:​:​error)​)​;​64
118 ······}65 ··void·do_read_header()​
119 ····}66 ··{
120 ····​else67 ····asio:​:​async_read(socket_,​
121 ····{68 ········asio:​:​buffer(read_msg_.​data()​,​·chat_message:​:​header_length)​,​
122 ······​do_close()​;​69 ········[this](std:​:​error_code·ec,​·std:​:​size_t·/​*length*/​)​
123 ····}70 ········{
124 ··}71 ··········if·(!ec·&&·read_msg_.​decode_header()​)​
125 72 ··········{
126 ··void·​do_close()​73 ············​do_read_body()​;​
127 ··{74 ··········}
128 ····socket_.​close()​;​75 ··········else
76 ··········​{
77 ············​socket_.​close()​;​
78 ··········​}
79 ········​})​;​
80 ··​}
81
82 ··​void·​do_read_body()​
83 ··​{
84 ····​asio:​:​async_read(socket_,​
85 ········​asio:​:​buffer(read_msg_.​body()​,​·​read_msg_.​body_length()​)​,​
86 ········​[this](std:​:​error_code·​ec,​·​std:​:​size_t·​/​*length*/​)​
87 ········​{
88 ··········​if·​(!ec)​
89 ··········​{
90 ············​std:​:​cout.​write(read_msg_.​body()​,​·​read_msg_.​body_length()​)​;​
91 ············​std:​:​cout·​<<·​"\n";​
92 ············​do_read_header()​;​
93 ··········​}
94 ··········​else
95 ··········​{
96 ············​socket_.​close()​;​
97 ··········​}
98 ········​})​;​
99 ··​}
100
101 ··​void·​do_write()​
102 ··​{
103 ····​asio:​:​async_write(socket_,​
104 ········​asio:​:​buffer(write_msgs_.​front()​.​data()​,​
105 ··········​write_msgs_.​front()​.​length()​)​,​
106 ········​[this](std:​:​error_code·​ec,​·​std:​:​size_t·​/​*length*/​)​
107 ········​{
108 ··········​if·​(!ec)​
109 ··········​{
110 ············​write_msgs_.​pop_front()​;​
111 ············​if·​(!write_msgs_.​empty()​)​
112 ············​{
113 ··············​do_write()​;​
114 ············​}
115 ··········​}
116 ··········​else
117 ··········​{
118 ············​socket_.​close()​;​
119 ··········​}
120 ········​})​;​
129 ··​}121 ··​}
130 122
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 }