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