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 }