]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // |
92f5a8d4 | 2 | // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
7c673cae FG |
3 | // |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | ||
8 | /** | |
9 | \page tutdaytime1 Daytime.1 - A synchronous TCP daytime client | |
10 | ||
11 | This tutorial program shows how to use asio to implement a client application | |
12 | with TCP. | |
13 | ||
14 | \dontinclude daytime1/client.cpp | |
15 | \skip #include | |
16 | ||
17 | We start by including the necessary header files. | |
18 | ||
19 | \until asio.hpp | |
20 | ||
21 | The purpose of this application is to access a daytime service, | |
22 | so we need the user to specify the server. | |
23 | ||
24 | \until } | |
25 | ||
11fdf7f2 | 26 | All programs that use asio need to have at least one boost::asio::io_context |
7c673cae FG |
27 | object. |
28 | ||
11fdf7f2 | 29 | \until boost::asio::io_context |
7c673cae FG |
30 | |
31 | We need to turn the server name that was specified as a parameter to the | |
32 | application, into a TCP endpoint. To do this we use an | |
33 | boost::asio::ip::tcp::resolver object. | |
34 | ||
35 | \until tcp::resolver | |
36 | ||
37 | A resolver takes a query object and turns it into a list of endpoints. We | |
38 | construct a query using the name of the server, specified in <tt>argv[1]</tt>, | |
39 | and the name of the service, in this case <tt>"daytime"</tt>. | |
40 | ||
41 | \until tcp::resolver::query | |
42 | ||
43 | The list of endpoints is returned using an iterator of type | |
44 | boost::asio::ip::tcp::resolver::iterator. (Note that a default constructed | |
45 | boost::asio::ip::tcp::resolver::iterator object can be used as an end iterator.) | |
46 | ||
47 | \until tcp::resolver::iterator | |
48 | ||
49 | Now we create and connect the socket. The list of endpoints obtained above may | |
50 | contain both IPv4 and IPv6 endpoints, so we need to try each of them until we | |
51 | find one that works. This keeps the client program independent of a specific IP | |
52 | version. The boost::asio::connect() function does this for us automatically. | |
53 | ||
54 | \until boost::asio::connect | |
55 | ||
56 | The connection is open. All we need to do now is read the response from the | |
57 | daytime service. | |
58 | ||
59 | We use a <tt>boost::array</tt> to hold the received data. The boost::asio::buffer() | |
60 | function automatically determines the size of the array to help prevent buffer | |
61 | overruns. Instead of a <tt>boost::array</tt>, we could have used a <tt>char | |
62 | []</tt> or <tt>std::vector</tt>. | |
63 | ||
64 | \until read_some | |
65 | ||
66 | When the server closes the connection, the boost::asio::ip::tcp::socket::read_some() | |
67 | function will exit with the boost::asio::error::eof error, which is how we know to | |
68 | exit the loop. | |
69 | ||
70 | \until } | |
71 | ||
72 | Finally, handle any exceptions that may have been thrown. | |
73 | ||
74 | \until } | |
75 | \until } | |
76 | ||
77 | See the \ref tutdaytime1src "full source listing" \n | |
78 | Return to the \ref index "tutorial index" \n | |
79 | Next: \ref tutdaytime2 | |
80 | ||
81 | */ | |
82 | ||
83 | /** | |
84 | \page tutdaytime1src Source listing for Daytime.1 | |
85 | \include daytime1/client.cpp | |
86 | Return to \ref tutdaytime1 | |
87 | */ | |
88 | ||
89 | /** | |
90 | \page tutdaytime2 Daytime.2 - A synchronous TCP daytime server | |
91 | ||
92 | This tutorial program shows how to use asio to implement a server application | |
93 | with TCP. | |
94 | ||
95 | \dontinclude daytime2/server.cpp | |
96 | \skip #include | |
97 | ||
98 | \until using | |
99 | ||
100 | We define the function <tt>make_daytime_string()</tt> to create the string to | |
101 | be sent back to the client. This function will be reused in all of our daytime | |
102 | server applications. | |
103 | ||
11fdf7f2 | 104 | \until boost::asio::io_context |
7c673cae FG |
105 | |
106 | A boost::asio::ip::tcp::acceptor object needs to be created to listen | |
107 | for new connections. It is initialised to listen on TCP port 13, for IP version 4. | |
108 | ||
109 | \until tcp::acceptor | |
110 | ||
111 | This is an iterative server, which means that it will handle one | |
112 | connection at a time. Create a socket that will represent the connection to the | |
113 | client, and then wait for a connection. | |
114 | ||
115 | \until acceptor.accept | |
116 | ||
117 | A client is accessing our service. Determine the current time | |
118 | and transfer this information to the client. | |
119 | ||
120 | \until } | |
121 | \until } | |
122 | ||
123 | Finally, handle any exceptions. | |
124 | ||
125 | \until } | |
126 | \until } | |
127 | ||
128 | See the \ref tutdaytime2src "full source listing" \n | |
129 | Return to the \ref index "tutorial index" \n | |
130 | Previous: \ref tutdaytime1 \n | |
131 | Next: \ref tutdaytime3 | |
132 | ||
133 | */ | |
134 | ||
135 | /** | |
136 | \page tutdaytime2src Source listing for Daytime.2 | |
137 | \include daytime2/server.cpp | |
138 | Return to \ref tutdaytime2 | |
139 | */ | |
140 | ||
141 | /** | |
142 | \page tutdaytime3 Daytime.3 - An asynchronous TCP daytime server | |
143 | ||
144 | \section tutdaytime3funcmain The main() function | |
145 | ||
146 | \dontinclude daytime3/server.cpp | |
147 | \skip int main() | |
148 | \until try | |
149 | \until { | |
150 | ||
151 | We need to create a server object to accept incoming client connections. The | |
11fdf7f2 | 152 | boost::asio::io_context object provides I/O services, such as sockets, that the |
7c673cae FG |
153 | server object will use. |
154 | ||
155 | \until tcp_server | |
156 | ||
11fdf7f2 | 157 | Run the boost::asio::io_context object so that it will perform asynchronous operations |
7c673cae FG |
158 | on your behalf. |
159 | ||
160 | \until return 0; | |
161 | \until } | |
162 | ||
163 | \section tutdaytime3classtcp_server The tcp_server class | |
164 | ||
165 | \dontinclude daytime3/server.cpp | |
166 | \skip class tcp_server | |
167 | \until public: | |
168 | ||
169 | The constructor initialises an acceptor to listen on TCP port 13. | |
170 | ||
171 | \until private: | |
172 | ||
173 | The function <tt>start_accept()</tt> creates a socket and initiates an | |
174 | asynchronous accept operation to wait for a new connection. | |
175 | ||
176 | \until } | |
177 | ||
178 | The function <tt>handle_accept()</tt> is called when the asynchronous accept | |
179 | operation initiated by <tt>start_accept()</tt> finishes. It services the client | |
180 | request, and then calls <tt>start_accept()</tt> to initiate the next accept | |
181 | operation. | |
182 | ||
183 | \until } | |
184 | \until } | |
185 | ||
186 | \section tutdaytime3classtcp_connection The tcp_connection class | |
187 | ||
188 | We will use <tt>shared_ptr</tt> and <tt>enable_shared_from_this</tt> because we | |
189 | want to keep the <tt>tcp_connection</tt> object alive as long as there is an | |
190 | operation that refers to it. | |
191 | ||
192 | \dontinclude daytime3/server.cpp | |
193 | \skip class tcp_connection | |
194 | \until shared_ptr | |
195 | \until } | |
196 | \until } | |
197 | ||
198 | In the function <tt>start()</tt>, we call boost::asio::async_write() to serve the data | |
199 | to the client. Note that we are using boost::asio::async_write(), rather than | |
200 | boost::asio::ip::tcp::socket::async_write_some(), to ensure that the entire block of | |
201 | data is sent. | |
202 | ||
203 | \until { | |
204 | ||
205 | The data to be sent is stored in the class member <tt>message_</tt> as we need | |
206 | to keep the data valid until the asynchronous operation is complete. | |
207 | ||
208 | \until message_ | |
209 | ||
210 | When initiating the asynchronous operation, and if using boost::bind(), you | |
211 | must specify only the arguments that match the handler's parameter list. In | |
212 | this program, both of the argument placeholders (boost::asio::placeholders::error and | |
213 | boost::asio::placeholders::bytes_transferred) could potentially have been removed, | |
214 | since they are not being used in <tt>handle_write()</tt>. | |
215 | ||
216 | \until placeholders::bytes_transferred | |
217 | ||
218 | Any further actions for this client connection are now the responsibility of | |
219 | <tt>handle_write()</tt>. | |
220 | ||
221 | \until }; | |
222 | ||
223 | \section tutdaytime3remunused Removing unused handler parameters | |
224 | ||
225 | You may have noticed that the <tt>error</tt>, and <tt>bytes_transferred</tt> | |
226 | parameters are not used in the body of the <tt>handle_write()</tt> function. If | |
227 | parameters are not needed, it is possible to remove them from the function so | |
228 | that it looks like: | |
229 | ||
230 | \code | |
231 | void handle_write() | |
232 | { | |
233 | } | |
234 | \endcode | |
235 | ||
236 | The boost::asio::async_write() call used to initiate the call can then be changed to | |
237 | just: | |
238 | ||
239 | \code | |
240 | boost::asio::async_write(socket_, boost::asio::buffer(message_), | |
241 | boost::bind(&tcp_connection::handle_write, shared_from_this())); | |
242 | \endcode | |
243 | ||
244 | See the \ref tutdaytime3src "full source listing" \n | |
245 | Return to the \ref index "tutorial index" \n | |
246 | Previous: \ref tutdaytime2 \n | |
247 | Next: \ref tutdaytime4 | |
248 | ||
249 | */ | |
250 | ||
251 | /** | |
252 | \page tutdaytime3src Source listing for Daytime.3 | |
253 | \include daytime3/server.cpp | |
254 | Return to \ref tutdaytime3 | |
255 | */ | |
256 | ||
257 | /** | |
258 | \page tutdaytime4 Daytime.4 - A synchronous UDP daytime client | |
259 | ||
260 | This tutorial program shows how to use asio to implement a client application | |
261 | with UDP. | |
262 | ||
263 | \dontinclude daytime4/client.cpp | |
264 | \skip #include | |
265 | \until using boost::asio::ip::udp; | |
266 | ||
267 | The start of the application is essentially the same as for the TCP daytime | |
268 | client. | |
269 | ||
11fdf7f2 | 270 | \until boost::asio::io_context |
7c673cae FG |
271 | |
272 | We use an boost::asio::ip::udp::resolver object to find the correct remote endpoint to | |
273 | use based on the host and service names. The query is restricted to return only | |
274 | IPv4 endpoints by the boost::asio::ip::udp::v4() argument. | |
275 | ||
276 | \until udp::v4 | |
277 | ||
278 | The boost::asio::ip::udp::resolver::resolve() function is guaranteed to return at | |
279 | least one endpoint in the list if it does not fail. This means it is safe to | |
280 | dereference the return value directly. | |
281 | ||
282 | \until udp::endpoint | |
283 | ||
284 | Since UDP is datagram-oriented, we will not be using a stream socket. Create an | |
285 | boost::asio::ip::udp::socket and initiate contact with the remote endpoint. | |
286 | ||
287 | \until receiver_endpoint | |
288 | ||
289 | Now we need to be ready to accept whatever the server sends back to us. The | |
290 | endpoint on our side that receives the server's response will be initialised by | |
291 | boost::asio::ip::udp::socket::receive_from(). | |
292 | ||
293 | \until } | |
294 | ||
295 | Finally, handle any exceptions that may have been thrown. | |
296 | ||
297 | \until } | |
298 | \until } | |
299 | See the \ref tutdaytime4src "full source listing" \n | |
300 | Return to the \ref index "tutorial index" \n | |
301 | Previous: \ref tutdaytime3 \n | |
302 | Next: \ref tutdaytime5 | |
303 | ||
304 | */ | |
305 | ||
306 | /** | |
307 | \page tutdaytime4src Source listing for Daytime.4 | |
308 | \include daytime4/client.cpp | |
309 | Return to \ref tutdaytime4 | |
310 | */ | |
311 | ||
312 | /** | |
313 | \page tutdaytime5 Daytime.5 - A synchronous UDP daytime server | |
314 | ||
315 | This tutorial program shows how to use asio to implement a server application | |
316 | with UDP. | |
317 | ||
318 | \dontinclude daytime5/server.cpp | |
319 | \skip int main() | |
11fdf7f2 | 320 | \until boost::asio::io_context |
7c673cae FG |
321 | |
322 | Create an boost::asio::ip::udp::socket object to receive requests on UDP port 13. | |
323 | ||
324 | \until udp::socket | |
325 | ||
326 | Wait for a client to initiate contact with us. The remote_endpoint object will | |
327 | be populated by boost::asio::ip::udp::socket::receive_from(). | |
328 | ||
92f5a8d4 | 329 | \until receive_from |
7c673cae FG |
330 | |
331 | Determine what we are going to send back to the client. | |
332 | ||
333 | \until std::string message | |
334 | ||
335 | Send the response to the remote_endpoint. | |
336 | ||
337 | \until } | |
338 | \until } | |
339 | ||
340 | Finally, handle any exceptions. | |
341 | ||
342 | \until } | |
343 | \until } | |
344 | ||
345 | See the \ref tutdaytime5src "full source listing" \n | |
346 | Return to the \ref index "tutorial index" \n | |
347 | Previous: \ref tutdaytime4 \n | |
348 | Next: \ref tutdaytime6 | |
349 | ||
350 | */ | |
351 | ||
352 | /** | |
353 | \page tutdaytime5src Source listing for Daytime.5 | |
354 | \include daytime5/server.cpp | |
355 | Return to \ref tutdaytime5 | |
356 | */ | |
357 | ||
358 | /** | |
359 | \page tutdaytime6 Daytime.6 - An asynchronous UDP daytime server | |
360 | ||
361 | \section tutdaytime6funcmain The main() function | |
362 | ||
363 | \dontinclude daytime6/server.cpp | |
364 | \skip int main() | |
365 | \until try | |
366 | \until { | |
367 | ||
368 | Create a server object to accept incoming client requests, and run | |
11fdf7f2 | 369 | the boost::asio::io_context object. |
7c673cae FG |
370 | |
371 | \until return 0; | |
372 | \until } | |
373 | ||
374 | \section tutdaytime6classudp_server The udp_server class | |
375 | ||
376 | \dontinclude daytime6/server.cpp | |
377 | \skip class udp_server | |
378 | \until public: | |
379 | ||
380 | The constructor initialises a socket to listen on UDP port 13. | |
381 | ||
382 | \until private: | |
383 | \until { | |
384 | ||
385 | The function boost::asio::ip::udp::socket::async_receive_from() will cause the | |
386 | application to listen in the background for a new request. When such a request | |
11fdf7f2 | 387 | is received, the boost::asio::io_context object will invoke the |
7c673cae FG |
388 | <tt>handle_receive()</tt> function with two arguments: a value of type |
389 | boost::system::error_code indicating whether the operation succeeded or failed, and a | |
390 | <tt>size_t</tt> value <tt>bytes_transferred</tt> specifying the number of bytes | |
391 | received. | |
392 | ||
393 | \until } | |
394 | ||
395 | The function <tt>handle_receive()</tt> will service the client request. | |
396 | ||
397 | \until { | |
398 | ||
399 | The <tt>error</tt> parameter contains the result of the asynchronous operation. | |
400 | Since we only provide the 1-byte <tt>recv_buffer_</tt> to contain the client's | |
11fdf7f2 | 401 | request, the boost::asio::io_context object would return an error if the client sent |
7c673cae FG |
402 | anything larger. We can ignore such an error if it comes up. |
403 | ||
404 | \until { | |
405 | ||
406 | Determine what we are going to send. | |
407 | ||
408 | \until make_daytime_string() | |
409 | ||
410 | We now call boost::asio::ip::udp::socket::async_send_to() to serve the data to the | |
411 | client. | |
412 | ||
413 | \until boost::asio::placeholders::bytes_transferred | |
414 | ||
415 | When initiating the asynchronous operation, and if using boost::bind(), you | |
416 | must specify only the arguments that match the handler's parameter list. In | |
417 | this program, both of the argument placeholders (boost::asio::placeholders::error and | |
418 | boost::asio::placeholders::bytes_transferred) could potentially have been removed. | |
419 | ||
420 | Start listening for the next client request. | |
421 | ||
422 | \until start_receive | |
423 | ||
424 | Any further actions for this client request are now the responsibility of | |
425 | <tt>handle_send()</tt>. | |
426 | ||
427 | \until } | |
428 | \until } | |
429 | ||
430 | The function <tt>handle_send()</tt> is invoked after the service request has | |
431 | been completed. | |
432 | ||
433 | \until } | |
434 | \until } | |
435 | ||
436 | See the \ref tutdaytime6src "full source listing" \n | |
437 | Return to the \ref index "tutorial index" \n | |
438 | Previous: \ref tutdaytime5 \n | |
439 | Next: \ref tutdaytime7 | |
440 | ||
441 | */ | |
442 | ||
443 | /** | |
444 | \page tutdaytime6src Source listing for Daytime.6 | |
445 | \include daytime6/server.cpp | |
446 | Return to \ref tutdaytime6 | |
447 | */ | |
448 | ||
449 | /** | |
450 | \page tutdaytime7 Daytime.7 - A combined TCP/UDP asynchronous server | |
451 | ||
452 | This tutorial program shows how to combine the two asynchronous servers that we | |
453 | have just written, into a single server application. | |
454 | ||
455 | \section tutdaytime7funcmain The main() function | |
456 | ||
457 | \dontinclude daytime7/server.cpp | |
458 | \skip int main() | |
11fdf7f2 | 459 | \until boost::asio::io_context |
7c673cae FG |
460 | |
461 | We will begin by creating a server object to accept a TCP client connection. | |
462 | ||
463 | \until tcp_server | |
464 | ||
465 | We also need a server object to accept a UDP client request. | |
466 | ||
467 | \until udp_server | |
468 | ||
11fdf7f2 | 469 | We have created two lots of work for the boost::asio::io_context object to do. |
7c673cae FG |
470 | |
471 | \until return 0; | |
472 | \until } | |
473 | ||
474 | \section tutdaytime7classtcp The tcp_connection and tcp_server classes | |
475 | ||
476 | The following two classes are taken from \ref tutdaytime3 "Daytime.3". | |
477 | ||
478 | \dontinclude daytime7/server.cpp | |
479 | \skip class tcp_connection | |
480 | \until }; | |
481 | \until }; | |
482 | ||
483 | \section tutdaytime7classudp The udp_server class | |
484 | ||
485 | Similarly, this next class is taken from the | |
486 | \ref tutdaytime6 "previous tutorial step". | |
487 | ||
488 | \dontinclude daytime7/server.cpp | |
489 | \skip class udp_server | |
490 | \until }; | |
491 | ||
492 | See the \ref tutdaytime7src "full source listing" \n | |
493 | Return to the \ref index "tutorial index" \n | |
494 | Previous: \ref tutdaytime6 | |
495 | ||
496 | */ | |
497 | ||
498 | /** | |
499 | \page tutdaytime7src Source listing for Daytime.7 | |
500 | \include daytime7/server.cpp | |
501 | Return to \ref tutdaytime7 | |
502 | */ |