]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/asio/doc/tutorial.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / asio / doc / tutorial.qbk
CommitLineData
7c673cae
FG
1[/
2 / Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
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[section:tutorial Tutorial]
9
10[heading Basic Skills]
11
12The tutorial programs in this first section introduce the fundamental concepts required to use the asio toolkit. Before plunging into the complex world of network programming, these tutorial programs illustrate the basic skills using simple asynchronous timers.
13
14* [link boost_asio.tutorial.tuttimer1 Timer.1 - Using a timer synchronously]
15
16
17* [link boost_asio.tutorial.tuttimer2 Timer.2 - Using a timer asynchronously]
18
19
20* [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler]
21
22
23* [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler]
24
25
26* [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs]
27
28
29
30
31[heading Introduction to Sockets]
32
33The tutorial programs in this section show how to use asio to develop simple client and server programs. These tutorial programs are based around the [@http://www.ietf.org/rfc/rfc867.txt daytime] protocol, which supports both TCP and UDP.
34
35The first three tutorial programs implement the daytime protocol using TCP.
36
37* [link boost_asio.tutorial.tutdaytime1 Daytime.1 - A synchronous TCP daytime client]
38
39
40* [link boost_asio.tutorial.tutdaytime2 Daytime.2 - A synchronous TCP daytime server]
41
42
43* [link boost_asio.tutorial.tutdaytime3 Daytime.3 - An asynchronous TCP daytime server]
44
45
46
47The next three tutorial programs implement the daytime protocol using UDP.
48
49* [link boost_asio.tutorial.tutdaytime4 Daytime.4 - A synchronous UDP daytime client]
50
51
52* [link boost_asio.tutorial.tutdaytime5 Daytime.5 - A synchronous UDP daytime server]
53
54
55* [link boost_asio.tutorial.tutdaytime6 Daytime.6 - An asynchronous UDP daytime server]
56
57
58
59The last tutorial program in this section demonstrates how asio allows the TCP and UDP servers to be easily combined into a single program.
60
61* [link boost_asio.tutorial.tutdaytime7 Daytime.7 - A combined TCP/UDP asynchronous server]
62
63
64
65
66[section:tuttimer1 Timer.1 - Using a timer synchronously]
67
68This tutorial program introduces asio by showing how to perform a blocking wait on a timer.
69
70
71
72
73
74We start by including the necessary header files.
75
76All of the asio classes can be used by simply including the `"asio.hpp"` header file.
77
78
79 ``''''''``#include <iostream>
80 ``''''''``#include <boost/asio.hpp>
81
82
83
84Since this example uses timers, we need to include the appropriate Boost.Date\_Time header file for manipulating times.
85
86
87 ``''''''``#include <boost/date_time/posix_time/posix_time.hpp>
88
89
90
91All programs that use asio need to have at least one
92[link boost_asio.reference.io_service io_service] object. This class provides access to I/O functionality. We declare an object of this type first thing in the main function.
93
94
95
96 ``''''''``int main()
97 ``''''''``{
98 ``''''''`` boost::asio::io_service io;
99
100
101
102Next we declare an object of type boost::asio::deadline\_timer. The core asio classes that provide I/O functionality (or as in this case timer functionality) always take a reference to an io\_service as their first constructor argument. The second argument to the constructor sets the timer to expire 5 seconds from now.
103
104
105
106 ``''''''`` boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
107
108
109
110In this simple example we perform a blocking wait on the timer. That is, the call to [link boost_asio.reference.basic_deadline_timer.wait deadline_timer::wait()] will not return until the timer has expired, 5 seconds after it was created (i.e. not from when the wait starts).
111
112A deadline timer is always in one of two states: "expired" or "not expired". If the [link boost_asio.reference.basic_deadline_timer.wait deadline_timer::wait()] function is called on an expired timer, it will return immediately.
113
114
115 ``''''''`` t.wait();
116
117
118
119Finally we print the obligatory `"Hello, world!"` message to show when the timer has expired.
120
121
122
123 ``''''''`` std::cout << "Hello, world!" << std::endl;
124
125 ``''''''`` return 0;
126 ``''''''``}
127
128
129
130See the [link boost_asio.tutorial.tuttimer1.src full source listing]
131
132Return to the [link boost_asio.tutorial tutorial index]
133
134Next: [link boost_asio.tutorial.tuttimer2 Timer.2 - Using a timer asynchronously]
135
136
137
138[section:src Source listing for Timer.1]
139
140
141 ``''''''``//
142 ``''''''``// timer.cpp
143 ``''''''``// ~~~~~~~~~
144 ``''''''``//
145 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
146 ``''''''``//
147 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
148 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
149 ``''''''``//
150
151 ``''''''``#include <iostream>
152 ``''''''``#include <boost/asio.hpp>
153 ``''''''``#include <boost/date_time/posix_time/posix_time.hpp>
154
155 ``''''''``int main()
156 ``''''''``{
157 ``''''''`` boost::asio::io_service io;
158
159 ``''''''`` boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
160 ``''''''`` t.wait();
161
162 ``''''''`` std::cout << "Hello, world!" << std::endl;
163
164 ``''''''`` return 0;
165 ``''''''``}
166
167Return to [link boost_asio.tutorial.tuttimer1 Timer.1 - Using a timer synchronously]
168
169[endsect]
170
171[endsect]
172
173[section:tuttimer2 Timer.2 - Using a timer asynchronously]
174
175This tutorial program demonstrates how to use asio's asynchronous callback functionality by modifying the program from tutorial Timer.1 to perform an asynchronous wait on the timer.
176
177
178
179
180
181
182 ``''''''``#include <iostream>
183 ``''''''``#include <boost/asio.hpp>
184 ``''''''``#include <boost/date_time/posix_time/posix_time.hpp>
185
186
187
188Using asio's asynchronous functionality means having a callback function that will be called when an asynchronous operation completes. In this program we define a function called `print` to be called when the asynchronous wait finishes.
189
190
191
192 ``''''''``void print(const boost::system::error_code& /*e*/)
193 ``''''''``{
194 ``''''''`` std::cout << "Hello, world!" << std::endl;
195 ``''''''``}
196
197 ``''''''``int main()
198 ``''''''``{
199 ``''''''`` boost::asio::io_service io;
200
201 ``''''''`` boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
202
203
204
205Next, instead of doing a blocking wait as in tutorial Timer.1, we call the [link boost_asio.reference.basic_deadline_timer.async_wait deadline_timer::async_wait()] function to perform an asynchronous wait. When calling this function we pass the `print` callback handler that was defined above.
206
207
208 ``''''''`` t.async_wait(&print);
209
210
211
212Finally, we must call the [link boost_asio.reference.io_service.run io_service::run()] member function on the io\_service object.
213
214The asio library provides a guarantee that callback handlers will only be called from threads that are currently calling [link boost_asio.reference.io_service.run io_service::run()]. Therefore unless the [link boost_asio.reference.io_service.run io_service::run()] function is called the callback for the asynchronous wait completion will never be invoked.
215
216The [link boost_asio.reference.io_service.run io_service::run()] function will also continue to run while there is still "work" to do. In this example, the work is the asynchronous wait on the timer, so the call will not return until the timer has expired and the callback has completed.
217
218It is important to remember to give the io\_service some work to do before calling [link boost_asio.reference.io_service.run io_service::run()]. For example, if we had omitted the above call to [link boost_asio.reference.basic_deadline_timer.async_wait deadline_timer::async_wait()], the io\_service would not have had any work to do, and consequently [link boost_asio.reference.io_service.run io_service::run()] would have returned immediately.
219
220
221 ``''''''`` io.run();
222
223 ``''''''`` return 0;
224 ``''''''``}
225
226
227
228See the [link boost_asio.tutorial.tuttimer2.src full source listing]
229
230Return to the [link boost_asio.tutorial tutorial index]
231
232Previous: [link boost_asio.tutorial.tuttimer1 Timer.1 - Using a timer synchronously]
233
234Next: [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler]
235
236
237
238[section:src Source listing for Timer.2]
239
240
241 ``''''''``//
242 ``''''''``// timer.cpp
243 ``''''''``// ~~~~~~~~~
244 ``''''''``//
245 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
246 ``''''''``//
247 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
248 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
249 ``''''''``//
250
251 ``''''''``#include <iostream>
252 ``''''''``#include <boost/asio.hpp>
253 ``''''''``#include <boost/date_time/posix_time/posix_time.hpp>
254
255 ``''''''``void print(const boost::system::error_code& /*e*/)
256 ``''''''``{
257 ``''''''`` std::cout << "Hello, world!" << std::endl;
258 ``''''''``}
259
260 ``''''''``int main()
261 ``''''''``{
262 ``''''''`` boost::asio::io_service io;
263
264 ``''''''`` boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
265 ``''''''`` t.async_wait(&print);
266
267 ``''''''`` io.run();
268
269 ``''''''`` return 0;
270 ``''''''``}
271
272Return to [link boost_asio.tutorial.tuttimer2 Timer.2 - Using a timer asynchronously]
273
274[endsect]
275
276[endsect]
277
278[section:tuttimer3 Timer.3 - Binding arguments to a handler]
279
280In this tutorial we will modify the program from tutorial Timer.2 so that the timer fires once a second. This will show how to pass additional parameters to your handler function.
281
282
283
284
285
286
287 ``''''''``#include <iostream>
288 ``''''''``#include <boost/asio.hpp>
289 ``''''''``#include <boost/bind.hpp>
290 ``''''''``#include <boost/date_time/posix_time/posix_time.hpp>
291
292
293
294To implement a repeating timer using asio you need to change the timer's expiry time in your callback function, and to then start a new asynchronous wait. Obviously this means that the callback function will need to be able to access the timer object. To this end we add two new parameters to the `print` function:
295
296* A pointer to a timer object.
297
298
299* A counter so that we can stop the program when the timer fires for the sixth time.
300
301
302
303
304 ``''''''``void print(const boost::system::error_code& /*e*/,
305 ``''''''`` boost::asio::deadline_timer* t, int* count)
306 ``''''''``{
307
308
309
310As mentioned above, this tutorial program uses a counter to stop running when the timer fires for the sixth time. However you will observe that there is no explicit call to ask the io\_service to stop. Recall that in tutorial Timer.2 we learnt that the [link boost_asio.reference.io_service.run io_service::run()] function completes when there is no more "work" to do. By not starting a new asynchronous wait on the timer when `count` reaches 5, the io\_service will run out of work and stop running.
311
312
313 ``''''''`` if (*count < 5)
314 ``''''''`` {
315 ``''''''`` std::cout << *count << std::endl;
316 ``''''''`` ++(*count);
317
318
319
320Next we move the expiry time for the timer along by one second from the previous expiry time. By calculating the new expiry time relative to the old, we can ensure that the timer does not drift away from the whole-second mark due to any delays in processing the handler.
321
322
323
324 ``''''''`` t->expires_at(t->expires_at() + boost::posix_time::seconds(1));
325
326
327
328Then we start a new asynchronous wait on the timer. As you can see, the boost::bind() function is used to associate the extra parameters with your callback handler. The [link boost_asio.reference.basic_deadline_timer.async_wait deadline_timer::async_wait()] function expects a handler function (or function object) with the signature `void(const boost::system::error_code&)`. Binding the additional parameters converts your `print` function into a function object that matches the signature correctly.
329
330See the [@http://www.boost.org/libs/bind/bind.html Boost.Bind documentation] for more information on how to use boost::bind().
331
332In this example, the boost::asio::placeholders::error argument to boost::bind() is a named placeholder for the error object passed to the handler. When initiating the asynchronous operation, and if using boost::bind(), you must specify only the arguments that match the handler's parameter list. In tutorial Timer.4 you will see that this placeholder may be elided if the parameter is not needed by the callback handler.
333
334
335 ``''''''`` t->async_wait(boost::bind(print,
336 ``''''''`` boost::asio::placeholders::error, t, count));
337 ``''''''`` }
338 ``''''''``}
339
340 ``''''''``int main()
341 ``''''''``{
342 ``''''''`` boost::asio::io_service io;
343
344
345
346A new `count` variable is added so that we can stop the program when the timer fires for the sixth time.
347
348
349
350 ``''''''`` int count = 0;
351 ``''''''`` boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
352
353
354
355As in Step 4, when making the call to [link boost_asio.reference.basic_deadline_timer.async_wait deadline_timer::async_wait()] from `main` we bind the additional parameters needed for the `print` function.
356
357
358 ``''''''`` t.async_wait(boost::bind(print,
359 ``''''''`` boost::asio::placeholders::error, &t, &count));
360
361 ``''''''`` io.run();
362
363
364
365Finally, just to prove that the `count` variable was being used in the `print` handler function, we will print out its new value.
366
367
368
369 ``''''''`` std::cout << "Final count is " << count << std::endl;
370
371 ``''''''`` return 0;
372 ``''''''``}
373
374
375
376See the [link boost_asio.tutorial.tuttimer3.src full source listing]
377
378Return to the [link boost_asio.tutorial tutorial index]
379
380Previous: [link boost_asio.tutorial.tuttimer2 Timer.2 - Using a timer asynchronously]
381
382Next: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler]
383
384
385
386[section:src Source listing for Timer.3]
387
388
389 ``''''''``//
390 ``''''''``// timer.cpp
391 ``''''''``// ~~~~~~~~~
392 ``''''''``//
393 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
394 ``''''''``//
395 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
396 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
397 ``''''''``//
398
399 ``''''''``#include <iostream>
400 ``''''''``#include <boost/asio.hpp>
401 ``''''''``#include <boost/bind.hpp>
402 ``''''''``#include <boost/date_time/posix_time/posix_time.hpp>
403
404 ``''''''``void print(const boost::system::error_code& /*e*/,
405 ``''''''`` boost::asio::deadline_timer* t, int* count)
406 ``''''''``{
407 ``''''''`` if (*count < 5)
408 ``''''''`` {
409 ``''''''`` std::cout << *count << std::endl;
410 ``''''''`` ++(*count);
411
412 ``''''''`` t->expires_at(t->expires_at() + boost::posix_time::seconds(1));
413 ``''''''`` t->async_wait(boost::bind(print,
414 ``''''''`` boost::asio::placeholders::error, t, count));
415 ``''''''`` }
416 ``''''''``}
417
418 ``''''''``int main()
419 ``''''''``{
420 ``''''''`` boost::asio::io_service io;
421
422 ``''''''`` int count = 0;
423 ``''''''`` boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
424 ``''''''`` t.async_wait(boost::bind(print,
425 ``''''''`` boost::asio::placeholders::error, &t, &count));
426
427 ``''''''`` io.run();
428
429 ``''''''`` std::cout << "Final count is " << count << std::endl;
430
431 ``''''''`` return 0;
432 ``''''''``}
433
434Return to [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler]
435
436[endsect]
437
438[endsect]
439
440[section:tuttimer4 Timer.4 - Using a member function as a handler]
441
442In this tutorial we will see how to use a class member function as a callback handler. The program should execute identically to the tutorial program from tutorial Timer.3.
443
444
445
446
447
448
449 ``''''''``#include <iostream>
450 ``''''''``#include <boost/asio.hpp>
451 ``''''''``#include <boost/bind.hpp>
452 ``''''''``#include <boost/date_time/posix_time/posix_time.hpp>
453
454
455
456Instead of defining a free function `print` as the callback handler, as we did in the earlier tutorial programs, we now define a class called `printer`.
457
458
459
460 ``''''''``class printer
461 ``''''''``{
462 ``''''''``public:
463
464
465
466The constructor of this class will take a reference to the io\_service object and use it when initialising the `timer_` member. The counter used to shut down the program is now also a member of the class.
467
468
469 ``''''''`` printer(boost::asio::io_service& io)
470 ``''''''`` : timer_(io, boost::posix_time::seconds(1)),
471 ``''''''`` count_(0)
472 ``''''''`` {
473
474
475
476The boost::bind() function works just as well with class member functions as with free functions. Since all non-static class member functions have an implicit `this` parameter, we need to bind `this` to the function. As in tutorial Timer.3, boost::bind() converts our callback handler (now a member function) into a function object that can be invoked as though it has the signature `void(const boost::system::error_code&)`.
477
478You will note that the boost::asio::placeholders::error placeholder is not specified here, as the `print` member function does not accept an error object as a parameter.
479
480
481 ``''''''`` timer_.async_wait(boost::bind(&printer::print, this));
482 ``''''''`` }
483
484
485
486In the class destructor we will print out the final value of the counter.
487
488
489
490 ``''''''`` ~printer()
491 ``''''''`` {
492 ``''''''`` std::cout << "Final count is " << count_ << std::endl;
493 ``''''''`` }
494
495
496
497The `print` member function is very similar to the `print` function from tutorial Timer.3, except that it now operates on the class data members instead of having the timer and counter passed in as parameters.
498
499
500
501 ``''''''`` void print()
502 ``''''''`` {
503 ``''''''`` if (count_ < 5)
504 ``''''''`` {
505 ``''''''`` std::cout << count_ << std::endl;
506 ``''''''`` ++count_;
507
508 ``''''''`` timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
509 ``''''''`` timer_.async_wait(boost::bind(&printer::print, this));
510 ``''''''`` }
511 ``''''''`` }
512
513 ``''''''``private:
514 ``''''''`` boost::asio::deadline_timer timer_;
515 ``''''''`` int count_;
516 ``''''''``};
517
518
519
520The `main` function is much simpler than before, as it now declares a local `printer` object before running the io\_service as normal.
521
522
523
524 ``''''''``int main()
525 ``''''''``{
526 ``''''''`` boost::asio::io_service io;
527 ``''''''`` printer p(io);
528 ``''''''`` io.run();
529
530 ``''''''`` return 0;
531 ``''''''``}
532
533
534
535See the [link boost_asio.tutorial.tuttimer4.src full source listing]
536
537Return to the [link boost_asio.tutorial tutorial index]
538
539Previous: [link boost_asio.tutorial.tuttimer3 Timer.3 - Binding arguments to a handler]
540
541Next: [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs]
542
543
544
545
546
547[section:src Source listing for Timer.4]
548
549
550 ``''''''``//
551 ``''''''``// timer.cpp
552 ``''''''``// ~~~~~~~~~
553 ``''''''``//
554 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
555 ``''''''``//
556 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
557 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
558 ``''''''``//
559
560 ``''''''``#include <iostream>
561 ``''''''``#include <boost/asio.hpp>
562 ``''''''``#include <boost/bind.hpp>
563 ``''''''``#include <boost/date_time/posix_time/posix_time.hpp>
564
565 ``''''''``class printer
566 ``''''''``{
567 ``''''''``public:
568 ``''''''`` printer(boost::asio::io_service& io)
569 ``''''''`` : timer_(io, boost::posix_time::seconds(1)),
570 ``''''''`` count_(0)
571 ``''''''`` {
572 ``''''''`` timer_.async_wait(boost::bind(&printer::print, this));
573 ``''''''`` }
574
575 ``''''''`` ~printer()
576 ``''''''`` {
577 ``''''''`` std::cout << "Final count is " << count_ << std::endl;
578 ``''''''`` }
579
580 ``''''''`` void print()
581 ``''''''`` {
582 ``''''''`` if (count_ < 5)
583 ``''''''`` {
584 ``''''''`` std::cout << count_ << std::endl;
585 ``''''''`` ++count_;
586
587 ``''''''`` timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
588 ``''''''`` timer_.async_wait(boost::bind(&printer::print, this));
589 ``''''''`` }
590 ``''''''`` }
591
592 ``''''''``private:
593 ``''''''`` boost::asio::deadline_timer timer_;
594 ``''''''`` int count_;
595 ``''''''``};
596
597 ``''''''``int main()
598 ``''''''``{
599 ``''''''`` boost::asio::io_service io;
600 ``''''''`` printer p(io);
601 ``''''''`` io.run();
602
603 ``''''''`` return 0;
604 ``''''''``}
605
606Return to [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler]
607
608[endsect]
609
610[endsect]
611
612[section:tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs]
613
614This tutorial demonstrates the use of the boost::asio::strand class to synchronise callback handlers in a multithreaded program.
615
616The previous four tutorials avoided the issue of handler synchronisation by calling the [link boost_asio.reference.io_service.run io_service::run()] function from one thread only. As you already know, the asio library provides a guarantee that callback handlers will only be called from threads that are currently calling [link boost_asio.reference.io_service.run io_service::run()]. Consequently, calling [link boost_asio.reference.io_service.run io_service::run()] from only one thread ensures that callback handlers cannot run concurrently.
617
618The single threaded approach is usually the best place to start when developing applications using asio. The downside is the limitations it places on programs, particularly servers, including:
619
620* Poor responsiveness when handlers can take a long time to complete.
621
622
623* An inability to scale on multiprocessor systems.
624
625
626
627
628If you find yourself running into these limitations, an alternative approach is to have a pool of threads calling [link boost_asio.reference.io_service.run io_service::run()]. However, as this allows handlers to execute concurrently, we need a method of synchronisation when handlers might be accessing a shared, thread-unsafe resource.
629
630
631
632
633
634
635 ``''''''``#include <iostream>
636 ``''''''``#include <boost/asio.hpp>
637 ``''''''``#include <boost/thread/thread.hpp>
638 ``''''''``#include <boost/bind.hpp>
639 ``''''''``#include <boost/date_time/posix_time/posix_time.hpp>
640
641
642
643We start by defining a class called `printer`, similar to the class in the previous tutorial. This class will extend the previous tutorial by running two timers in parallel.
644
645
646
647 ``''''''``class printer
648 ``''''''``{
649 ``''''''``public:
650
651
652
653In addition to initialising a pair of boost::asio::deadline\_timer members, the constructor initialises the `strand_` member, an object of type boost::asio::strand.
654
655An boost::asio::strand guarantees that, for those handlers that are dispatched through it, an executing handler will be allowed to complete before the next one is started. This is guaranteed irrespective of the number of threads that are calling [link boost_asio.reference.io_service.run io_service::run()]. Of course, the handlers may still execute concurrently with other handlers that were not dispatched through an boost::asio::strand, or were dispatched through a different boost::asio::strand object.
656
657
658 ``''''''`` printer(boost::asio::io_service& io)
659 ``''''''`` : strand_(io),
660 ``''''''`` timer1_(io, boost::posix_time::seconds(1)),
661 ``''''''`` timer2_(io, boost::posix_time::seconds(1)),
662 ``''''''`` count_(0)
663 ``''''''`` {
664
665
666
667When initiating the asynchronous operations, each callback handler is "wrapped" using the boost::asio::strand object. The [link boost_asio.reference.io_service__strand.wrap strand::wrap()] function returns a new handler that automatically dispatches its contained handler through the boost::asio::strand object. By wrapping the handlers using the same boost::asio::strand, we are ensuring that they cannot execute concurrently.
668
669
670 ``''''''`` timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
671 ``''''''`` timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));
672 ``''''''`` }
673
674 ``''''''`` ~printer()
675 ``''''''`` {
676 ``''''''`` std::cout << "Final count is " << count_ << std::endl;
677 ``''''''`` }
678
679
680
681In a multithreaded program, the handlers for asynchronous operations should be synchronised if they access shared resources. In this tutorial, the shared resources used by the handlers (`print1` and `print2`) are `std::cout` and the `count_` data member.
682
683
684
685 ``''''''`` void print1()
686 ``''''''`` {
687 ``''''''`` if (count_ < 10)
688 ``''''''`` {
689 ``''''''`` std::cout << "Timer 1: " << count_ << std::endl;
690 ``''''''`` ++count_;
691
692 ``''''''`` timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1));
693 ``''''''`` timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
694 ``''''''`` }
695 ``''''''`` }
696
697 ``''''''`` void print2()
698 ``''''''`` {
699 ``''''''`` if (count_ < 10)
700 ``''''''`` {
701 ``''''''`` std::cout << "Timer 2: " << count_ << std::endl;
702 ``''''''`` ++count_;
703
704 ``''''''`` timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1));
705 ``''''''`` timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));
706 ``''''''`` }
707 ``''''''`` }
708
709 ``''''''``private:
710 ``''''''`` boost::asio::io_service::strand strand_;
711 ``''''''`` boost::asio::deadline_timer timer1_;
712 ``''''''`` boost::asio::deadline_timer timer2_;
713 ``''''''`` int count_;
714 ``''''''``};
715
716
717
718The `main` function now causes [link boost_asio.reference.io_service.run io_service::run()] to be called from two threads: the main thread and one additional thread. This is accomplished using an boost::thread object.
719
720Just as it would with a call from a single thread, concurrent calls to [link boost_asio.reference.io_service.run io_service::run()] will continue to execute while there is "work" left to do. The background thread will not exit until all asynchronous operations have completed.
721
722
723
724 ``''''''``int main()
725 ``''''''``{
726 ``''''''`` boost::asio::io_service io;
727 ``''''''`` printer p(io);
728 ``''''''`` boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
729 ``''''''`` io.run();
730 ``''''''`` t.join();
731
732 ``''''''`` return 0;
733 ``''''''``}
734
735
736
737See the [link boost_asio.tutorial.tuttimer5.src full source listing]
738
739Return to the [link boost_asio.tutorial tutorial index]
740
741Previous: [link boost_asio.tutorial.tuttimer4 Timer.4 - Using a member function as a handler]
742
743
744
745
746
747[section:src Source listing for Timer.5]
748
749
750 ``''''''``//
751 ``''''''``// timer.cpp
752 ``''''''``// ~~~~~~~~~
753 ``''''''``//
754 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
755 ``''''''``//
756 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
757 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
758 ``''''''``//
759
760 ``''''''``#include <iostream>
761 ``''''''``#include <boost/asio.hpp>
762 ``''''''``#include <boost/thread/thread.hpp>
763 ``''''''``#include <boost/bind.hpp>
764 ``''''''``#include <boost/date_time/posix_time/posix_time.hpp>
765
766 ``''''''``class printer
767 ``''''''``{
768 ``''''''``public:
769 ``''''''`` printer(boost::asio::io_service& io)
770 ``''''''`` : strand_(io),
771 ``''''''`` timer1_(io, boost::posix_time::seconds(1)),
772 ``''''''`` timer2_(io, boost::posix_time::seconds(1)),
773 ``''''''`` count_(0)
774 ``''''''`` {
775 ``''''''`` timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
776 ``''''''`` timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));
777 ``''''''`` }
778
779 ``''''''`` ~printer()
780 ``''''''`` {
781 ``''''''`` std::cout << "Final count is " << count_ << std::endl;
782 ``''''''`` }
783
784 ``''''''`` void print1()
785 ``''''''`` {
786 ``''''''`` if (count_ < 10)
787 ``''''''`` {
788 ``''''''`` std::cout << "Timer 1: " << count_ << std::endl;
789 ``''''''`` ++count_;
790
791 ``''''''`` timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(1));
792 ``''''''`` timer1_.async_wait(strand_.wrap(boost::bind(&printer::print1, this)));
793 ``''''''`` }
794 ``''''''`` }
795
796 ``''''''`` void print2()
797 ``''''''`` {
798 ``''''''`` if (count_ < 10)
799 ``''''''`` {
800 ``''''''`` std::cout << "Timer 2: " << count_ << std::endl;
801 ``''''''`` ++count_;
802
803 ``''''''`` timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(1));
804 ``''''''`` timer2_.async_wait(strand_.wrap(boost::bind(&printer::print2, this)));
805 ``''''''`` }
806 ``''''''`` }
807
808 ``''''''``private:
809 ``''''''`` boost::asio::io_service::strand strand_;
810 ``''''''`` boost::asio::deadline_timer timer1_;
811 ``''''''`` boost::asio::deadline_timer timer2_;
812 ``''''''`` int count_;
813 ``''''''``};
814
815 ``''''''``int main()
816 ``''''''``{
817 ``''''''`` boost::asio::io_service io;
818 ``''''''`` printer p(io);
819 ``''''''`` boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
820 ``''''''`` io.run();
821 ``''''''`` t.join();
822
823 ``''''''`` return 0;
824 ``''''''``}
825
826Return to [link boost_asio.tutorial.tuttimer5 Timer.5 - Synchronising handlers in multithreaded programs]
827
828[endsect]
829
830[endsect]
831
832[section:tutdaytime1 Daytime.1 - A synchronous TCP daytime client]
833
834This tutorial program shows how to use asio to implement a client application with TCP.
835
836
837
838
839
840We start by including the necessary header files.
841
842
843 ``''''''``#include <iostream>
844 ``''''''``#include <boost/array.hpp>
845 ``''''''``#include <boost/asio.hpp>
846
847
848
849The purpose of this application is to access a daytime service, so we need the user to specify the server.
850
851
852
853 ``''''''``using boost::asio::ip::tcp;
854
855 ``''''''``int main(int argc, char* argv[])
856 ``''''''``{
857 ``''''''`` try
858 ``''''''`` {
859 ``''''''`` if (argc != 2)
860 ``''''''`` {
861 ``''''''`` std::cerr << "Usage: client <host>" << std::endl;
862 ``''''''`` return 1;
863 ``''''''`` }
864
865
866
867All programs that use asio need to have at least one
868[link boost_asio.reference.io_service io_service] object.
869
870
871
872 ``''''''`` boost::asio::io_service io_service;
873
874
875
876We need to turn the server name that was specified as a parameter to the application, into a TCP endpoint. To do this we use an [link boost_asio.reference.ip__tcp.resolver ip::tcp::resolver] object.
877
878
879
880 ``''''''`` tcp::resolver resolver(io_service);
881
882
883
884A resolver takes a query object and turns it into a list of endpoints. We construct a query using the name of the server, specified in `argv[1]`, and the name of the service, in this case `"daytime"`.
885
886
887 ``''''''`` tcp::resolver::query query(argv[1], "daytime");
888
889
890
891The list of endpoints is returned using an iterator of type [link boost_asio.reference.ip__basic_resolver.iterator ip::tcp::resolver::iterator]. (Note that a default constructed [link boost_asio.reference.ip__basic_resolver.iterator ip::tcp::resolver::iterator] object can be used as an end iterator.)
892
893
894 ``''''''`` tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
895
896
897
898Now we create and connect the socket. The list of endpoints obtained above may contain both IPv4 and IPv6 endpoints, so we need to try each of them until we find one that works. This keeps the client program independent of a specific IP version. The boost::asio::connect() function does this for us automatically.
899
900
901
902 ``''''''`` tcp::socket socket(io_service);
903 ``''''''`` boost::asio::connect(socket, endpoint_iterator);
904
905
906
907The connection is open. All we need to do now is read the response from the daytime service.
908
909We use a `boost::array` to hold the received data. The boost::asio::buffer() function automatically determines the size of the array to help prevent buffer overruns. Instead of a `boost::array`, we could have used a `char []` or `std::vector`.
910
911
912
913 ``''''''`` for (;;)
914 ``''''''`` {
915 ``''''''`` boost::array<char, 128> buf;
916 ``''''''`` boost::system::error_code error;
917
918 ``''''''`` size_t len = socket.read_some(boost::asio::buffer(buf), error);
919
920
921
922When the server closes the connection, the [link boost_asio.reference.basic_stream_socket.read_some ip::tcp::socket::read_some()] function will exit with the boost::asio::error::eof error, which is how we know to exit the loop.
923
924
925
926 ``''''''`` if (error == boost::asio::error::eof)
927 ``''''''`` break; // Connection closed cleanly by peer.
928 ``''''''`` else if (error)
929 ``''''''`` throw boost::system::system_error(error); // Some other error.
930
931 ``''''''`` std::cout.write(buf.data(), len);
932 ``''''''`` }
933
934
935
936Finally, handle any exceptions that may have been thrown.
937
938
939 ``''''''`` }
940 ``''''''`` catch (std::exception& e)
941 ``''''''`` {
942 ``''''''`` std::cerr << e.what() << std::endl;
943 ``''''''`` }
944
945
946
947See the [link boost_asio.tutorial.tutdaytime1.src full source listing]
948
949Return to the [link boost_asio.tutorial tutorial index]
950
951Next: [link boost_asio.tutorial.tutdaytime2 Daytime.2 - A synchronous TCP daytime server]
952
953
954
955[section:src Source listing for Daytime.1]
956
957
958 ``''''''``//
959 ``''''''``// client.cpp
960 ``''''''``// ~~~~~~~~~~
961 ``''''''``//
962 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
963 ``''''''``//
964 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
965 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
966 ``''''''``//
967
968 ``''''''``#include <iostream>
969 ``''''''``#include <boost/array.hpp>
970 ``''''''``#include <boost/asio.hpp>
971
972 ``''''''``using boost::asio::ip::tcp;
973
974 ``''''''``int main(int argc, char* argv[])
975 ``''''''``{
976 ``''''''`` try
977 ``''''''`` {
978 ``''''''`` if (argc != 2)
979 ``''''''`` {
980 ``''''''`` std::cerr << "Usage: client <host>" << std::endl;
981 ``''''''`` return 1;
982 ``''''''`` }
983
984 ``''''''`` boost::asio::io_service io_service;
985
986 ``''''''`` tcp::resolver resolver(io_service);
987 ``''''''`` tcp::resolver::query query(argv[1], "daytime");
988 ``''''''`` tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
989
990 ``''''''`` tcp::socket socket(io_service);
991 ``''''''`` boost::asio::connect(socket, endpoint_iterator);
992
993 ``''''''`` for (;;)
994 ``''''''`` {
995 ``''''''`` boost::array<char, 128> buf;
996 ``''''''`` boost::system::error_code error;
997
998 ``''''''`` size_t len = socket.read_some(boost::asio::buffer(buf), error);
999
1000 ``''''''`` if (error == boost::asio::error::eof)
1001 ``''''''`` break; // Connection closed cleanly by peer.
1002 ``''''''`` else if (error)
1003 ``''''''`` throw boost::system::system_error(error); // Some other error.
1004
1005 ``''''''`` std::cout.write(buf.data(), len);
1006 ``''''''`` }
1007 ``''''''`` }
1008 ``''''''`` catch (std::exception& e)
1009 ``''''''`` {
1010 ``''''''`` std::cerr << e.what() << std::endl;
1011 ``''''''`` }
1012
1013 ``''''''`` return 0;
1014 ``''''''``}
1015
1016Return to [link boost_asio.tutorial.tutdaytime1 Daytime.1 - A synchronous TCP daytime client]
1017
1018[endsect]
1019
1020[endsect]
1021
1022[section:tutdaytime2 Daytime.2 - A synchronous TCP daytime server]
1023
1024This tutorial program shows how to use asio to implement a server application with TCP.
1025
1026
1027
1028
1029
1030
1031 ``''''''``#include <ctime>
1032 ``''''''``#include <iostream>
1033 ``''''''``#include <string>
1034 ``''''''``#include <boost/asio.hpp>
1035
1036 ``''''''``using boost::asio::ip::tcp;
1037
1038
1039
1040We define the function `make_daytime_string()` to create the string to be sent back to the client. This function will be reused in all of our daytime server applications.
1041
1042
1043
1044 ``''''''``std::string make_daytime_string()
1045 ``''''''``{
1046 ``''''''`` using namespace std; // For time_t, time and ctime;
1047 ``''''''`` time_t now = time(0);
1048 ``''''''`` return ctime(&now);
1049 ``''''''``}
1050
1051 ``''''''``int main()
1052 ``''''''``{
1053 ``''''''`` try
1054 ``''''''`` {
1055 ``''''''`` boost::asio::io_service io_service;
1056
1057
1058
1059A [link boost_asio.reference.ip__tcp.acceptor ip::tcp::acceptor] object needs to be created to listen for new connections. It is initialised to listen on TCP port 13, for IP version 4.
1060
1061
1062
1063 ``''''''`` tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 13));
1064
1065
1066
1067This is an iterative server, which means that it will handle one connection at a time. Create a socket that will represent the connection to the client, and then wait for a connection.
1068
1069
1070
1071 ``''''''`` for (;;)
1072 ``''''''`` {
1073 ``''''''`` tcp::socket socket(io_service);
1074 ``''''''`` acceptor.accept(socket);
1075
1076
1077
1078A client is accessing our service. Determine the current time and transfer this information to the client.
1079
1080
1081
1082 ``''''''`` std::string message = make_daytime_string();
1083
1084 ``''''''`` boost::system::error_code ignored_error;
1085 ``''''''`` boost::asio::write(socket, boost::asio::buffer(message), ignored_error);
1086 ``''''''`` }
1087 ``''''''`` }
1088
1089
1090
1091Finally, handle any exceptions.
1092
1093
1094 ``''''''`` catch (std::exception& e)
1095 ``''''''`` {
1096 ``''''''`` std::cerr << e.what() << std::endl;
1097 ``''''''`` }
1098
1099 ``''''''`` return 0;
1100 ``''''''``}
1101
1102
1103
1104See the [link boost_asio.tutorial.tutdaytime2.src full source listing]
1105
1106Return to the [link boost_asio.tutorial tutorial index]
1107
1108Previous: [link boost_asio.tutorial.tutdaytime1 Daytime.1 - A synchronous TCP daytime client]
1109
1110Next: [link boost_asio.tutorial.tutdaytime3 Daytime.3 - An asynchronous TCP daytime server]
1111
1112
1113
1114[section:src Source listing for Daytime.2]
1115
1116
1117 ``''''''``//
1118 ``''''''``// server.cpp
1119 ``''''''``// ~~~~~~~~~~
1120 ``''''''``//
1121 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
1122 ``''''''``//
1123 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
1124 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1125 ``''''''``//
1126
1127 ``''''''``#include <ctime>
1128 ``''''''``#include <iostream>
1129 ``''''''``#include <string>
1130 ``''''''``#include <boost/asio.hpp>
1131
1132 ``''''''``using boost::asio::ip::tcp;
1133
1134 ``''''''``std::string make_daytime_string()
1135 ``''''''``{
1136 ``''''''`` using namespace std; // For time_t, time and ctime;
1137 ``''''''`` time_t now = time(0);
1138 ``''''''`` return ctime(&now);
1139 ``''''''``}
1140
1141 ``''''''``int main()
1142 ``''''''``{
1143 ``''''''`` try
1144 ``''''''`` {
1145 ``''''''`` boost::asio::io_service io_service;
1146
1147 ``''''''`` tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 13));
1148
1149 ``''''''`` for (;;)
1150 ``''''''`` {
1151 ``''''''`` tcp::socket socket(io_service);
1152 ``''''''`` acceptor.accept(socket);
1153
1154 ``''''''`` std::string message = make_daytime_string();
1155
1156 ``''''''`` boost::system::error_code ignored_error;
1157 ``''''''`` boost::asio::write(socket, boost::asio::buffer(message), ignored_error);
1158 ``''''''`` }
1159 ``''''''`` }
1160 ``''''''`` catch (std::exception& e)
1161 ``''''''`` {
1162 ``''''''`` std::cerr << e.what() << std::endl;
1163 ``''''''`` }
1164
1165 ``''''''`` return 0;
1166 ``''''''``}
1167
1168Return to [link boost_asio.tutorial.tutdaytime2 Daytime.2 - A synchronous TCP daytime server]
1169
1170[endsect]
1171
1172[endsect]
1173
1174[section:tutdaytime3 Daytime.3 - An asynchronous TCP daytime server]
1175
1176[heading The main() function]
1177
1178
1179 ``''''''``int main()
1180 ``''''''``{
1181 ``''''''`` try
1182 ``''''''`` {
1183
1184
1185
1186We need to create a server object to accept incoming client connections. The
1187[link boost_asio.reference.io_service io_service] object provides I/O services, such as sockets, that the server object will use.
1188
1189
1190 ``''''''`` boost::asio::io_service io_service;
1191 ``''''''`` tcp_server server(io_service);
1192
1193
1194
1195Run the
1196[link boost_asio.reference.io_service io_service] object so that it will perform asynchronous operations on your behalf.
1197
1198
1199 ``''''''`` io_service.run();
1200 ``''''''`` }
1201 ``''''''`` catch (std::exception& e)
1202 ``''''''`` {
1203 ``''''''`` std::cerr << e.what() << std::endl;
1204 ``''''''`` }
1205
1206 ``''''''`` return 0;
1207 ``''''''``}
1208
1209
1210
1211[heading The tcp_server class]
1212
1213
1214 ``''''''``class tcp_server
1215 ``''''''``{
1216 ``''''''``public:
1217
1218
1219
1220The constructor initialises an acceptor to listen on TCP port 13.
1221
1222
1223 ``''''''`` tcp_server(boost::asio::io_service& io_service)
1224 ``''''''`` : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
1225 ``''''''`` {
1226 ``''''''`` start_accept();
1227 ``''''''`` }
1228
1229 ``''''''``private:
1230
1231
1232
1233The function `start_accept()` creates a socket and initiates an asynchronous accept operation to wait for a new connection.
1234
1235
1236 ``''''''`` void start_accept()
1237 ``''''''`` {
1238 ``''''''`` tcp_connection::pointer new_connection =
1239 ``''''''`` tcp_connection::create(acceptor_.get_io_service());
1240
1241 ``''''''`` acceptor_.async_accept(new_connection->socket(),
1242 ``''''''`` boost::bind(&tcp_server::handle_accept, this, new_connection,
1243 ``''''''`` boost::asio::placeholders::error));
1244 ``''''''`` }
1245
1246
1247
1248The function `handle_accept()` is called when the asynchronous accept operation initiated by `start_accept()` finishes. It services the client request, and then calls `start_accept()` to initiate the next accept operation.
1249
1250
1251
1252 ``''''''`` void handle_accept(tcp_connection::pointer new_connection,
1253 ``''''''`` const boost::system::error_code& error)
1254 ``''''''`` {
1255 ``''''''`` if (!error)
1256 ``''''''`` {
1257 ``''''''`` new_connection->start();
1258 ``''''''`` }
1259
1260 ``''''''`` start_accept();
1261 ``''''''`` }
1262
1263
1264
1265[heading The tcp_connection class]
1266
1267We will use `shared_ptr` and `enable_shared_from_this` because we want to keep the `tcp_connection` object alive as long as there is an operation that refers to it.
1268
1269
1270 ``''''''``class tcp_connection
1271 ``''''''`` : public boost::enable_shared_from_this<tcp_connection>
1272 ``''''''``{
1273 ``''''''``public:
1274 ``''''''`` typedef boost::shared_ptr<tcp_connection> pointer;
1275
1276 ``''''''`` static pointer create(boost::asio::io_service& io_service)
1277 ``''''''`` {
1278 ``''''''`` return pointer(new tcp_connection(io_service));
1279 ``''''''`` }
1280
1281 ``''''''`` tcp::socket& socket()
1282 ``''''''`` {
1283 ``''''''`` return socket_;
1284 ``''''''`` }
1285
1286
1287
1288In the function `start()`, we call boost::asio::async\_write() to serve the data to the client. Note that we are using boost::asio::async\_write(), rather than [link boost_asio.reference.basic_stream_socket.async_write_some ip::tcp::socket::async_write_some()], to ensure that the entire block of data is sent.
1289
1290
1291
1292 ``''''''`` void start()
1293 ``''''''`` {
1294
1295
1296
1297The data to be sent is stored in the class member `message_` as we need to keep the data valid until the asynchronous operation is complete.
1298
1299
1300 ``''''''`` message_ = make_daytime_string();
1301
1302
1303
1304When initiating the asynchronous operation, and if using boost::bind(), you must specify only the arguments that match the handler's parameter list. In this program, both of the argument placeholders (boost::asio::placeholders::error and boost::asio::placeholders::bytes\_transferred) could potentially have been removed, since they are not being used in `handle_write()`.
1305
1306
1307
1308 ``''''''`` boost::asio::async_write(socket_, boost::asio::buffer(message_),
1309 ``''''''`` boost::bind(&tcp_connection::handle_write, shared_from_this(),
1310 ``''''''`` boost::asio::placeholders::error,
1311 ``''''''`` boost::asio::placeholders::bytes_transferred));
1312
1313
1314
1315Any further actions for this client connection are now the responsibility of `handle_write()`.
1316
1317
1318 ``''''''`` }
1319
1320 ``''''''``private:
1321 ``''''''`` tcp_connection(boost::asio::io_service& io_service)
1322 ``''''''`` : socket_(io_service)
1323 ``''''''`` {
1324 ``''''''`` }
1325
1326 ``''''''`` void handle_write(const boost::system::error_code& /*error*/,
1327 ``''''''`` size_t /*bytes_transferred*/)
1328 ``''''''`` {
1329 ``''''''`` }
1330
1331 ``''''''`` tcp::socket socket_;
1332 ``''''''`` std::string message_;
1333 ``''''''``};
1334
1335
1336
1337[heading Removing unused handler parameters]
1338
1339You may have noticed that the `error`, and `bytes_transferred` parameters are not used in the body of the `handle_write()` function. If parameters are not needed, it is possible to remove them from the function so that it looks like:
1340
1341
1342 ``''''''`` void handle_write()
1343 ``''''''`` {
1344 ``''''''`` }
1345
1346
1347
1348The boost::asio::async\_write() call used to initiate the call can then be changed to just:
1349
1350
1351 ``''''''`` boost::asio::async_write(socket_, boost::asio::buffer(message_),
1352 ``''''''`` boost::bind(&tcp_connection::handle_write, shared_from_this()));
1353
1354
1355
1356See the [link boost_asio.tutorial.tutdaytime3.src full source listing]
1357
1358Return to the [link boost_asio.tutorial tutorial index]
1359
1360Previous: [link boost_asio.tutorial.tutdaytime2 Daytime.2 - A synchronous TCP daytime server]
1361
1362Next: [link boost_asio.tutorial.tutdaytime4 Daytime.4 - A synchronous UDP daytime client]
1363
1364
1365
1366[section:src Source listing for Daytime.3]
1367
1368
1369 ``''''''``//
1370 ``''''''``// server.cpp
1371 ``''''''``// ~~~~~~~~~~
1372 ``''''''``//
1373 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
1374 ``''''''``//
1375 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
1376 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1377 ``''''''``//
1378
1379 ``''''''``#include <ctime>
1380 ``''''''``#include <iostream>
1381 ``''''''``#include <string>
1382 ``''''''``#include <boost/bind.hpp>
1383 ``''''''``#include <boost/shared_ptr.hpp>
1384 ``''''''``#include <boost/enable_shared_from_this.hpp>
1385 ``''''''``#include <boost/asio.hpp>
1386
1387 ``''''''``using boost::asio::ip::tcp;
1388
1389 ``''''''``std::string make_daytime_string()
1390 ``''''''``{
1391 ``''''''`` using namespace std; // For time_t, time and ctime;
1392 ``''''''`` time_t now = time(0);
1393 ``''''''`` return ctime(&now);
1394 ``''''''``}
1395
1396 ``''''''``class tcp_connection
1397 ``''''''`` : public boost::enable_shared_from_this<tcp_connection>
1398 ``''''''``{
1399 ``''''''``public:
1400 ``''''''`` typedef boost::shared_ptr<tcp_connection> pointer;
1401
1402 ``''''''`` static pointer create(boost::asio::io_service& io_service)
1403 ``''''''`` {
1404 ``''''''`` return pointer(new tcp_connection(io_service));
1405 ``''''''`` }
1406
1407 ``''''''`` tcp::socket& socket()
1408 ``''''''`` {
1409 ``''''''`` return socket_;
1410 ``''''''`` }
1411
1412 ``''''''`` void start()
1413 ``''''''`` {
1414 ``''''''`` message_ = make_daytime_string();
1415
1416 ``''''''`` boost::asio::async_write(socket_, boost::asio::buffer(message_),
1417 ``''''''`` boost::bind(&tcp_connection::handle_write, shared_from_this(),
1418 ``''''''`` boost::asio::placeholders::error,
1419 ``''''''`` boost::asio::placeholders::bytes_transferred));
1420 ``''''''`` }
1421
1422 ``''''''``private:
1423 ``''''''`` tcp_connection(boost::asio::io_service& io_service)
1424 ``''''''`` : socket_(io_service)
1425 ``''''''`` {
1426 ``''''''`` }
1427
1428 ``''''''`` void handle_write(const boost::system::error_code& /*error*/,
1429 ``''''''`` size_t /*bytes_transferred*/)
1430 ``''''''`` {
1431 ``''''''`` }
1432
1433 ``''''''`` tcp::socket socket_;
1434 ``''''''`` std::string message_;
1435 ``''''''``};
1436
1437 ``''''''``class tcp_server
1438 ``''''''``{
1439 ``''''''``public:
1440 ``''''''`` tcp_server(boost::asio::io_service& io_service)
1441 ``''''''`` : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
1442 ``''''''`` {
1443 ``''''''`` start_accept();
1444 ``''''''`` }
1445
1446 ``''''''``private:
1447 ``''''''`` void start_accept()
1448 ``''''''`` {
1449 ``''''''`` tcp_connection::pointer new_connection =
1450 ``''''''`` tcp_connection::create(acceptor_.get_io_service());
1451
1452 ``''''''`` acceptor_.async_accept(new_connection->socket(),
1453 ``''''''`` boost::bind(&tcp_server::handle_accept, this, new_connection,
1454 ``''''''`` boost::asio::placeholders::error));
1455 ``''''''`` }
1456
1457 ``''''''`` void handle_accept(tcp_connection::pointer new_connection,
1458 ``''''''`` const boost::system::error_code& error)
1459 ``''''''`` {
1460 ``''''''`` if (!error)
1461 ``''''''`` {
1462 ``''''''`` new_connection->start();
1463 ``''''''`` }
1464
1465 ``''''''`` start_accept();
1466 ``''''''`` }
1467
1468 ``''''''`` tcp::acceptor acceptor_;
1469 ``''''''``};
1470
1471 ``''''''``int main()
1472 ``''''''``{
1473 ``''''''`` try
1474 ``''''''`` {
1475 ``''''''`` boost::asio::io_service io_service;
1476 ``''''''`` tcp_server server(io_service);
1477 ``''''''`` io_service.run();
1478 ``''''''`` }
1479 ``''''''`` catch (std::exception& e)
1480 ``''''''`` {
1481 ``''''''`` std::cerr << e.what() << std::endl;
1482 ``''''''`` }
1483
1484 ``''''''`` return 0;
1485 ``''''''``}
1486
1487Return to [link boost_asio.tutorial.tutdaytime3 Daytime.3 - An asynchronous TCP daytime server]
1488
1489[endsect]
1490
1491[endsect]
1492
1493[section:tutdaytime4 Daytime.4 - A synchronous UDP daytime client]
1494
1495This tutorial program shows how to use asio to implement a client application with UDP.
1496
1497
1498 ``''''''``#include <iostream>
1499 ``''''''``#include <boost/array.hpp>
1500 ``''''''``#include <boost/asio.hpp>
1501
1502 ``''''''``using boost::asio::ip::udp;
1503
1504
1505
1506The start of the application is essentially the same as for the TCP daytime client.
1507
1508
1509
1510 ``''''''``int main(int argc, char* argv[])
1511 ``''''''``{
1512 ``''''''`` try
1513 ``''''''`` {
1514 ``''''''`` if (argc != 2)
1515 ``''''''`` {
1516 ``''''''`` std::cerr << "Usage: client <host>" << std::endl;
1517 ``''''''`` return 1;
1518 ``''''''`` }
1519
1520 ``''''''`` boost::asio::io_service io_service;
1521
1522
1523
1524We use an [link boost_asio.reference.ip__udp.resolver ip::udp::resolver] object to find the correct remote endpoint to use based on the host and service names. The query is restricted to return only IPv4 endpoints by the [link boost_asio.reference.ip__udp.v4 ip::udp::v4()] argument.
1525
1526
1527
1528 ``''''''`` udp::resolver resolver(io_service);
1529 ``''''''`` udp::resolver::query query(udp::v4(), argv[1], "daytime");
1530
1531
1532
1533The [link boost_asio.reference.ip__basic_resolver.resolve ip::udp::resolver::resolve()] function is guaranteed to return at least one endpoint in the list if it does not fail. This means it is safe to dereference the return value directly.
1534
1535
1536 ``''''''`` udp::endpoint receiver_endpoint = *resolver.resolve(query);
1537
1538
1539
1540Since UDP is datagram-oriented, we will not be using a stream socket. Create an [link boost_asio.reference.ip__udp.socket ip::udp::socket] and initiate contact with the remote endpoint.
1541
1542
1543
1544 ``''''''`` udp::socket socket(io_service);
1545 ``''''''`` socket.open(udp::v4());
1546
1547 ``''''''`` boost::array<char, 1> send_buf = {{ 0 }};
1548 ``''''''`` socket.send_to(boost::asio::buffer(send_buf), receiver_endpoint);
1549
1550
1551
1552Now we need to be ready to accept whatever the server sends back to us. The endpoint on our side that receives the server's response will be initialised by [link boost_asio.reference.basic_datagram_socket.receive_from ip::udp::socket::receive_from()].
1553
1554
1555
1556 ``''''''`` boost::array<char, 128> recv_buf;
1557 ``''''''`` udp::endpoint sender_endpoint;
1558 ``''''''`` size_t len = socket.receive_from(
1559 ``''''''`` boost::asio::buffer(recv_buf), sender_endpoint);
1560
1561 ``''''''`` std::cout.write(recv_buf.data(), len);
1562 ``''''''`` }
1563
1564
1565
1566Finally, handle any exceptions that may have been thrown.
1567
1568
1569 ``''''''`` catch (std::exception& e)
1570 ``''''''`` {
1571 ``''''''`` std::cerr << e.what() << std::endl;
1572 ``''''''`` }
1573
1574 ``''''''`` return 0;
1575 ``''''''``}
1576
1577See the [link boost_asio.tutorial.tutdaytime4.src full source listing]
1578
1579Return to the [link boost_asio.tutorial tutorial index]
1580
1581Previous: [link boost_asio.tutorial.tutdaytime3 Daytime.3 - An asynchronous TCP daytime server]
1582
1583Next: [link boost_asio.tutorial.tutdaytime5 Daytime.5 - A synchronous UDP daytime server]
1584
1585
1586
1587[section:src Source listing for Daytime.4]
1588
1589
1590 ``''''''``//
1591 ``''''''``// client.cpp
1592 ``''''''``// ~~~~~~~~~~
1593 ``''''''``//
1594 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
1595 ``''''''``//
1596 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
1597 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1598 ``''''''``//
1599
1600 ``''''''``#include <iostream>
1601 ``''''''``#include <boost/array.hpp>
1602 ``''''''``#include <boost/asio.hpp>
1603
1604 ``''''''``using boost::asio::ip::udp;
1605
1606 ``''''''``int main(int argc, char* argv[])
1607 ``''''''``{
1608 ``''''''`` try
1609 ``''''''`` {
1610 ``''''''`` if (argc != 2)
1611 ``''''''`` {
1612 ``''''''`` std::cerr << "Usage: client <host>" << std::endl;
1613 ``''''''`` return 1;
1614 ``''''''`` }
1615
1616 ``''''''`` boost::asio::io_service io_service;
1617
1618 ``''''''`` udp::resolver resolver(io_service);
1619 ``''''''`` udp::resolver::query query(udp::v4(), argv[1], "daytime");
1620 ``''''''`` udp::endpoint receiver_endpoint = *resolver.resolve(query);
1621
1622 ``''''''`` udp::socket socket(io_service);
1623 ``''''''`` socket.open(udp::v4());
1624
1625 ``''''''`` boost::array<char, 1> send_buf = {{ 0 }};
1626 ``''''''`` socket.send_to(boost::asio::buffer(send_buf), receiver_endpoint);
1627
1628 ``''''''`` boost::array<char, 128> recv_buf;
1629 ``''''''`` udp::endpoint sender_endpoint;
1630 ``''''''`` size_t len = socket.receive_from(
1631 ``''''''`` boost::asio::buffer(recv_buf), sender_endpoint);
1632
1633 ``''''''`` std::cout.write(recv_buf.data(), len);
1634 ``''''''`` }
1635 ``''''''`` catch (std::exception& e)
1636 ``''''''`` {
1637 ``''''''`` std::cerr << e.what() << std::endl;
1638 ``''''''`` }
1639
1640 ``''''''`` return 0;
1641 ``''''''``}
1642
1643Return to [link boost_asio.tutorial.tutdaytime4 Daytime.4 - A synchronous UDP daytime client]
1644
1645[endsect]
1646
1647[endsect]
1648
1649[section:tutdaytime5 Daytime.5 - A synchronous UDP daytime server]
1650
1651This tutorial program shows how to use asio to implement a server application with UDP.
1652
1653
1654 ``''''''``int main()
1655 ``''''''``{
1656 ``''''''`` try
1657 ``''''''`` {
1658 ``''''''`` boost::asio::io_service io_service;
1659
1660
1661
1662Create an [link boost_asio.reference.ip__udp.socket ip::udp::socket] object to receive requests on UDP port 13.
1663
1664
1665
1666 ``''''''`` udp::socket socket(io_service, udp::endpoint(udp::v4(), 13));
1667
1668
1669
1670Wait for a client to initiate contact with us. The remote\_endpoint object will be populated by [link boost_asio.reference.basic_datagram_socket.receive_from ip::udp::socket::receive_from()].
1671
1672
1673
1674 ``''''''`` for (;;)
1675 ``''''''`` {
1676 ``''''''`` boost::array<char, 1> recv_buf;
1677 ``''''''`` udp::endpoint remote_endpoint;
1678 ``''''''`` boost::system::error_code error;
1679 ``''''''`` socket.receive_from(boost::asio::buffer(recv_buf),
1680 ``''''''`` remote_endpoint, 0, error);
1681
1682 ``''''''`` if (error && error != boost::asio::error::message_size)
1683 ``''''''`` throw boost::system::system_error(error);
1684
1685
1686
1687Determine what we are going to send back to the client.
1688
1689
1690
1691 ``''''''`` std::string message = make_daytime_string();
1692
1693
1694
1695Send the response to the remote\_endpoint.
1696
1697
1698
1699 ``''''''`` boost::system::error_code ignored_error;
1700 ``''''''`` socket.send_to(boost::asio::buffer(message),
1701 ``''''''`` remote_endpoint, 0, ignored_error);
1702 ``''''''`` }
1703 ``''''''`` }
1704
1705
1706
1707Finally, handle any exceptions.
1708
1709
1710 ``''''''`` catch (std::exception& e)
1711 ``''''''`` {
1712 ``''''''`` std::cerr << e.what() << std::endl;
1713 ``''''''`` }
1714
1715 ``''''''`` return 0;
1716 ``''''''``}
1717
1718
1719
1720See the [link boost_asio.tutorial.tutdaytime5.src full source listing]
1721
1722Return to the [link boost_asio.tutorial tutorial index]
1723
1724Previous: [link boost_asio.tutorial.tutdaytime4 Daytime.4 - A synchronous UDP daytime client]
1725
1726Next: [link boost_asio.tutorial.tutdaytime6 Daytime.6 - An asynchronous UDP daytime server]
1727
1728
1729
1730[section:src Source listing for Daytime.5]
1731
1732
1733 ``''''''``//
1734 ``''''''``// server.cpp
1735 ``''''''``// ~~~~~~~~~~
1736 ``''''''``//
1737 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
1738 ``''''''``//
1739 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
1740 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1741 ``''''''``//
1742
1743 ``''''''``#include <ctime>
1744 ``''''''``#include <iostream>
1745 ``''''''``#include <string>
1746 ``''''''``#include <boost/array.hpp>
1747 ``''''''``#include <boost/asio.hpp>
1748
1749 ``''''''``using boost::asio::ip::udp;
1750
1751 ``''''''``std::string make_daytime_string()
1752 ``''''''``{
1753 ``''''''`` using namespace std; // For time_t, time and ctime;
1754 ``''''''`` time_t now = time(0);
1755 ``''''''`` return ctime(&now);
1756 ``''''''``}
1757
1758 ``''''''``int main()
1759 ``''''''``{
1760 ``''''''`` try
1761 ``''''''`` {
1762 ``''''''`` boost::asio::io_service io_service;
1763
1764 ``''''''`` udp::socket socket(io_service, udp::endpoint(udp::v4(), 13));
1765
1766 ``''''''`` for (;;)
1767 ``''''''`` {
1768 ``''''''`` boost::array<char, 1> recv_buf;
1769 ``''''''`` udp::endpoint remote_endpoint;
1770 ``''''''`` boost::system::error_code error;
1771 ``''''''`` socket.receive_from(boost::asio::buffer(recv_buf),
1772 ``''''''`` remote_endpoint, 0, error);
1773
1774 ``''''''`` if (error && error != boost::asio::error::message_size)
1775 ``''''''`` throw boost::system::system_error(error);
1776
1777 ``''''''`` std::string message = make_daytime_string();
1778
1779 ``''''''`` boost::system::error_code ignored_error;
1780 ``''''''`` socket.send_to(boost::asio::buffer(message),
1781 ``''''''`` remote_endpoint, 0, ignored_error);
1782 ``''''''`` }
1783 ``''''''`` }
1784 ``''''''`` catch (std::exception& e)
1785 ``''''''`` {
1786 ``''''''`` std::cerr << e.what() << std::endl;
1787 ``''''''`` }
1788
1789 ``''''''`` return 0;
1790 ``''''''``}
1791
1792Return to [link boost_asio.tutorial.tutdaytime5 Daytime.5 - A synchronous UDP daytime server]
1793
1794[endsect]
1795
1796[endsect]
1797
1798[section:tutdaytime6 Daytime.6 - An asynchronous UDP daytime server]
1799
1800[heading The main() function]
1801
1802
1803 ``''''''``int main()
1804 ``''''''``{
1805 ``''''''`` try
1806 ``''''''`` {
1807
1808
1809
1810Create a server object to accept incoming client requests, and run the
1811[link boost_asio.reference.io_service io_service] object.
1812
1813
1814 ``''''''`` boost::asio::io_service io_service;
1815 ``''''''`` udp_server server(io_service);
1816 ``''''''`` io_service.run();
1817 ``''''''`` }
1818 ``''''''`` catch (std::exception& e)
1819 ``''''''`` {
1820 ``''''''`` std::cerr << e.what() << std::endl;
1821 ``''''''`` }
1822
1823 ``''''''`` return 0;
1824 ``''''''``}
1825
1826
1827
1828[heading The udp_server class]
1829
1830
1831 ``''''''``class udp_server
1832 ``''''''``{
1833 ``''''''``public:
1834
1835
1836
1837The constructor initialises a socket to listen on UDP port 13.
1838
1839
1840 ``''''''`` udp_server(boost::asio::io_service& io_service)
1841 ``''''''`` : socket_(io_service, udp::endpoint(udp::v4(), 13))
1842 ``''''''`` {
1843 ``''''''`` start_receive();
1844 ``''''''`` }
1845
1846 ``''''''``private:
1847 ``''''''`` void start_receive()
1848 ``''''''`` {
1849
1850
1851
1852The function [link boost_asio.reference.basic_datagram_socket.async_receive_from ip::udp::socket::async_receive_from()] will cause the application to listen in the background for a new request. When such a request is received, the
1853[link boost_asio.reference.io_service io_service] object will invoke the `handle_receive()` function with two arguments: a value of type boost::system::error\_code indicating whether the operation succeeded or failed, and a `size_t` value `bytes_transferred` specifying the number of bytes received.
1854
1855
1856 ``''''''`` socket_.async_receive_from(
1857 ``''''''`` boost::asio::buffer(recv_buffer_), remote_endpoint_,
1858 ``''''''`` boost::bind(&udp_server::handle_receive, this,
1859 ``''''''`` boost::asio::placeholders::error,
1860 ``''''''`` boost::asio::placeholders::bytes_transferred));
1861 ``''''''`` }
1862
1863
1864
1865The function `handle_receive()` will service the client request.
1866
1867
1868
1869 ``''''''`` void handle_receive(const boost::system::error_code& error,
1870 ``''''''`` std::size_t /*bytes_transferred*/)
1871 ``''''''`` {
1872
1873
1874
1875The `error` parameter contains the result of the asynchronous operation. Since we only provide the 1-byte `recv_buffer_` to contain the client's request, the
1876[link boost_asio.reference.io_service io_service] object would return an error if the client sent anything larger. We can ignore such an error if it comes up.
1877
1878
1879 ``''''''`` if (!error || error == boost::asio::error::message_size)
1880 ``''''''`` {
1881
1882
1883
1884Determine what we are going to send.
1885
1886
1887 ``''''''`` boost::shared_ptr<std::string> message(
1888 ``''''''`` new std::string(make_daytime_string()));
1889
1890
1891
1892We now call [link boost_asio.reference.basic_datagram_socket.async_send_to ip::udp::socket::async_send_to()] to serve the data to the client.
1893
1894
1895
1896 ``''''''`` socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,
1897 ``''''''`` boost::bind(&udp_server::handle_send, this, message,
1898 ``''''''`` boost::asio::placeholders::error,
1899 ``''''''`` boost::asio::placeholders::bytes_transferred));
1900
1901
1902
1903When initiating the asynchronous operation, and if using boost::bind(), you must specify only the arguments that match the handler's parameter list. In this program, both of the argument placeholders (boost::asio::placeholders::error and boost::asio::placeholders::bytes\_transferred) could potentially have been removed.
1904
1905Start listening for the next client request.
1906
1907
1908
1909 ``''''''`` start_receive();
1910
1911
1912
1913Any further actions for this client request are now the responsibility of `handle_send()`.
1914
1915
1916 ``''''''`` }
1917 ``''''''`` }
1918
1919
1920
1921The function `handle_send()` is invoked after the service request has been completed.
1922
1923
1924
1925 ``''''''`` void handle_send(boost::shared_ptr<std::string> /*message*/,
1926 ``''''''`` const boost::system::error_code& /*error*/,
1927 ``''''''`` std::size_t /*bytes_transferred*/)
1928 ``''''''`` {
1929 ``''''''`` }
1930
1931 ``''''''`` udp::socket socket_;
1932 ``''''''`` udp::endpoint remote_endpoint_;
1933 ``''''''`` boost::array<char, 1> recv_buffer_;
1934 ``''''''``};
1935
1936
1937
1938See the [link boost_asio.tutorial.tutdaytime6.src full source listing]
1939
1940Return to the [link boost_asio.tutorial tutorial index]
1941
1942Previous: [link boost_asio.tutorial.tutdaytime5 Daytime.5 - A synchronous UDP daytime server]
1943
1944Next: [link boost_asio.tutorial.tutdaytime7 Daytime.7 - A combined TCP/UDP asynchronous server]
1945
1946
1947
1948[section:src Source listing for Daytime.6]
1949
1950
1951 ``''''''``//
1952 ``''''''``// server.cpp
1953 ``''''''``// ~~~~~~~~~~
1954 ``''''''``//
1955 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
1956 ``''''''``//
1957 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
1958 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1959 ``''''''``//
1960
1961 ``''''''``#include <ctime>
1962 ``''''''``#include <iostream>
1963 ``''''''``#include <string>
1964 ``''''''``#include <boost/array.hpp>
1965 ``''''''``#include <boost/bind.hpp>
1966 ``''''''``#include <boost/shared_ptr.hpp>
1967 ``''''''``#include <boost/asio.hpp>
1968
1969 ``''''''``using boost::asio::ip::udp;
1970
1971 ``''''''``std::string make_daytime_string()
1972 ``''''''``{
1973 ``''''''`` using namespace std; // For time_t, time and ctime;
1974 ``''''''`` time_t now = time(0);
1975 ``''''''`` return ctime(&now);
1976 ``''''''``}
1977
1978 ``''''''``class udp_server
1979 ``''''''``{
1980 ``''''''``public:
1981 ``''''''`` udp_server(boost::asio::io_service& io_service)
1982 ``''''''`` : socket_(io_service, udp::endpoint(udp::v4(), 13))
1983 ``''''''`` {
1984 ``''''''`` start_receive();
1985 ``''''''`` }
1986
1987 ``''''''``private:
1988 ``''''''`` void start_receive()
1989 ``''''''`` {
1990 ``''''''`` socket_.async_receive_from(
1991 ``''''''`` boost::asio::buffer(recv_buffer_), remote_endpoint_,
1992 ``''''''`` boost::bind(&udp_server::handle_receive, this,
1993 ``''''''`` boost::asio::placeholders::error,
1994 ``''''''`` boost::asio::placeholders::bytes_transferred));
1995 ``''''''`` }
1996
1997 ``''''''`` void handle_receive(const boost::system::error_code& error,
1998 ``''''''`` std::size_t /*bytes_transferred*/)
1999 ``''''''`` {
2000 ``''''''`` if (!error || error == boost::asio::error::message_size)
2001 ``''''''`` {
2002 ``''''''`` boost::shared_ptr<std::string> message(
2003 ``''''''`` new std::string(make_daytime_string()));
2004
2005 ``''''''`` socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,
2006 ``''''''`` boost::bind(&udp_server::handle_send, this, message,
2007 ``''''''`` boost::asio::placeholders::error,
2008 ``''''''`` boost::asio::placeholders::bytes_transferred));
2009
2010 ``''''''`` start_receive();
2011 ``''''''`` }
2012 ``''''''`` }
2013
2014 ``''''''`` void handle_send(boost::shared_ptr<std::string> /*message*/,
2015 ``''''''`` const boost::system::error_code& /*error*/,
2016 ``''''''`` std::size_t /*bytes_transferred*/)
2017 ``''''''`` {
2018 ``''''''`` }
2019
2020 ``''''''`` udp::socket socket_;
2021 ``''''''`` udp::endpoint remote_endpoint_;
2022 ``''''''`` boost::array<char, 1> recv_buffer_;
2023 ``''''''``};
2024
2025 ``''''''``int main()
2026 ``''''''``{
2027 ``''''''`` try
2028 ``''''''`` {
2029 ``''''''`` boost::asio::io_service io_service;
2030 ``''''''`` udp_server server(io_service);
2031 ``''''''`` io_service.run();
2032 ``''''''`` }
2033 ``''''''`` catch (std::exception& e)
2034 ``''''''`` {
2035 ``''''''`` std::cerr << e.what() << std::endl;
2036 ``''''''`` }
2037
2038 ``''''''`` return 0;
2039 ``''''''``}
2040
2041Return to [link boost_asio.tutorial.tutdaytime6 Daytime.6 - An asynchronous UDP daytime server]
2042
2043[endsect]
2044
2045[endsect]
2046
2047[section:tutdaytime7 Daytime.7 - A combined TCP/UDP asynchronous server]
2048
2049This tutorial program shows how to combine the two asynchronous servers that we have just written, into a single server application.
2050
2051[heading The main() function]
2052
2053
2054 ``''''''``int main()
2055 ``''''''``{
2056 ``''''''`` try
2057 ``''''''`` {
2058 ``''''''`` boost::asio::io_service io_service;
2059
2060
2061
2062We will begin by creating a server object to accept a TCP client connection.
2063
2064
2065 ``''''''`` tcp_server server1(io_service);
2066
2067
2068
2069We also need a server object to accept a UDP client request.
2070
2071
2072 ``''''''`` udp_server server2(io_service);
2073
2074
2075
2076We have created two lots of work for the
2077[link boost_asio.reference.io_service io_service] object to do.
2078
2079
2080 ``''''''`` io_service.run();
2081 ``''''''`` }
2082 ``''''''`` catch (std::exception& e)
2083 ``''''''`` {
2084 ``''''''`` std::cerr << e.what() << std::endl;
2085 ``''''''`` }
2086
2087 ``''''''`` return 0;
2088 ``''''''``}
2089
2090
2091
2092[heading The tcp_connection and tcp_server classes]
2093
2094The following two classes are taken from [link boost_asio.tutorial.tutdaytime3 Daytime.3] .
2095
2096
2097 ``''''''``class tcp_connection
2098 ``''''''`` : public boost::enable_shared_from_this<tcp_connection>
2099 ``''''''``{
2100 ``''''''``public:
2101 ``''''''`` typedef boost::shared_ptr<tcp_connection> pointer;
2102
2103 ``''''''`` static pointer create(boost::asio::io_service& io_service)
2104 ``''''''`` {
2105 ``''''''`` return pointer(new tcp_connection(io_service));
2106 ``''''''`` }
2107
2108 ``''''''`` tcp::socket& socket()
2109 ``''''''`` {
2110 ``''''''`` return socket_;
2111 ``''''''`` }
2112
2113 ``''''''`` void start()
2114 ``''''''`` {
2115 ``''''''`` message_ = make_daytime_string();
2116
2117 ``''''''`` boost::asio::async_write(socket_, boost::asio::buffer(message_),
2118 ``''''''`` boost::bind(&tcp_connection::handle_write, shared_from_this()));
2119 ``''''''`` }
2120
2121 ``''''''``private:
2122 ``''''''`` tcp_connection(boost::asio::io_service& io_service)
2123 ``''''''`` : socket_(io_service)
2124 ``''''''`` {
2125 ``''''''`` }
2126
2127 ``''''''`` void handle_write()
2128 ``''''''`` {
2129 ``''''''`` }
2130
2131 ``''''''`` tcp::socket socket_;
2132 ``''''''`` std::string message_;
2133 ``''''''``};
2134
2135 ``''''''``class tcp_server
2136 ``''''''``{
2137 ``''''''``public:
2138 ``''''''`` tcp_server(boost::asio::io_service& io_service)
2139 ``''''''`` : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
2140 ``''''''`` {
2141 ``''''''`` start_accept();
2142 ``''''''`` }
2143
2144 ``''''''``private:
2145 ``''''''`` void start_accept()
2146 ``''''''`` {
2147 ``''''''`` tcp_connection::pointer new_connection =
2148 ``''''''`` tcp_connection::create(acceptor_.get_io_service());
2149
2150 ``''''''`` acceptor_.async_accept(new_connection->socket(),
2151 ``''''''`` boost::bind(&tcp_server::handle_accept, this, new_connection,
2152 ``''''''`` boost::asio::placeholders::error));
2153 ``''''''`` }
2154
2155 ``''''''`` void handle_accept(tcp_connection::pointer new_connection,
2156 ``''''''`` const boost::system::error_code& error)
2157 ``''''''`` {
2158 ``''''''`` if (!error)
2159 ``''''''`` {
2160 ``''''''`` new_connection->start();
2161 ``''''''`` }
2162
2163 ``''''''`` start_accept();
2164 ``''''''`` }
2165
2166 ``''''''`` tcp::acceptor acceptor_;
2167 ``''''''``};
2168
2169
2170
2171[heading The udp_server class]
2172
2173Similarly, this next class is taken from the [link boost_asio.tutorial.tutdaytime6 previous tutorial step] .
2174
2175
2176 ``''''''``class udp_server
2177 ``''''''``{
2178 ``''''''``public:
2179 ``''''''`` udp_server(boost::asio::io_service& io_service)
2180 ``''''''`` : socket_(io_service, udp::endpoint(udp::v4(), 13))
2181 ``''''''`` {
2182 ``''''''`` start_receive();
2183 ``''''''`` }
2184
2185 ``''''''``private:
2186 ``''''''`` void start_receive()
2187 ``''''''`` {
2188 ``''''''`` socket_.async_receive_from(
2189 ``''''''`` boost::asio::buffer(recv_buffer_), remote_endpoint_,
2190 ``''''''`` boost::bind(&udp_server::handle_receive, this,
2191 ``''''''`` boost::asio::placeholders::error));
2192 ``''''''`` }
2193
2194 ``''''''`` void handle_receive(const boost::system::error_code& error)
2195 ``''''''`` {
2196 ``''''''`` if (!error || error == boost::asio::error::message_size)
2197 ``''''''`` {
2198 ``''''''`` boost::shared_ptr<std::string> message(
2199 ``''''''`` new std::string(make_daytime_string()));
2200
2201 ``''''''`` socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,
2202 ``''''''`` boost::bind(&udp_server::handle_send, this, message));
2203
2204 ``''''''`` start_receive();
2205 ``''''''`` }
2206 ``''''''`` }
2207
2208 ``''''''`` void handle_send(boost::shared_ptr<std::string> /*message*/)
2209 ``''''''`` {
2210 ``''''''`` }
2211
2212 ``''''''`` udp::socket socket_;
2213 ``''''''`` udp::endpoint remote_endpoint_;
2214 ``''''''`` boost::array<char, 1> recv_buffer_;
2215 ``''''''``};
2216
2217
2218
2219See the [link boost_asio.tutorial.tutdaytime7.src full source listing]
2220
2221Return to the [link boost_asio.tutorial tutorial index]
2222
2223Previous: [link boost_asio.tutorial.tutdaytime6 Daytime.6 - An asynchronous UDP daytime server]
2224
2225
2226
2227[section:src Source listing for Daytime.7]
2228
2229
2230 ``''''''``//
2231 ``''''''``// server.cpp
2232 ``''''''``// ~~~~~~~~~~
2233 ``''''''``//
2234 ``''''''``// Copyright (c) 2003-2016 Christopher M. Kohlhoff (chris at kohlhoff dot com)
2235 ``''''''``//
2236 ``''''''``// Distributed under the Boost Software License, Version 1.0. (See accompanying
2237 ``''''''``// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
2238 ``''''''``//
2239
2240 ``''''''``#include <ctime>
2241 ``''''''``#include <iostream>
2242 ``''''''``#include <string>
2243 ``''''''``#include <boost/array.hpp>
2244 ``''''''``#include <boost/bind.hpp>
2245 ``''''''``#include <boost/shared_ptr.hpp>
2246 ``''''''``#include <boost/enable_shared_from_this.hpp>
2247 ``''''''``#include <boost/asio.hpp>
2248
2249 ``''''''``using boost::asio::ip::tcp;
2250 ``''''''``using boost::asio::ip::udp;
2251
2252 ``''''''``std::string make_daytime_string()
2253 ``''''''``{
2254 ``''''''`` using namespace std; // For time_t, time and ctime;
2255 ``''''''`` time_t now = time(0);
2256 ``''''''`` return ctime(&now);
2257 ``''''''``}
2258
2259 ``''''''``class tcp_connection
2260 ``''''''`` : public boost::enable_shared_from_this<tcp_connection>
2261 ``''''''``{
2262 ``''''''``public:
2263 ``''''''`` typedef boost::shared_ptr<tcp_connection> pointer;
2264
2265 ``''''''`` static pointer create(boost::asio::io_service& io_service)
2266 ``''''''`` {
2267 ``''''''`` return pointer(new tcp_connection(io_service));
2268 ``''''''`` }
2269
2270 ``''''''`` tcp::socket& socket()
2271 ``''''''`` {
2272 ``''''''`` return socket_;
2273 ``''''''`` }
2274
2275 ``''''''`` void start()
2276 ``''''''`` {
2277 ``''''''`` message_ = make_daytime_string();
2278
2279 ``''''''`` boost::asio::async_write(socket_, boost::asio::buffer(message_),
2280 ``''''''`` boost::bind(&tcp_connection::handle_write, shared_from_this()));
2281 ``''''''`` }
2282
2283 ``''''''``private:
2284 ``''''''`` tcp_connection(boost::asio::io_service& io_service)
2285 ``''''''`` : socket_(io_service)
2286 ``''''''`` {
2287 ``''''''`` }
2288
2289 ``''''''`` void handle_write()
2290 ``''''''`` {
2291 ``''''''`` }
2292
2293 ``''''''`` tcp::socket socket_;
2294 ``''''''`` std::string message_;
2295 ``''''''``};
2296
2297 ``''''''``class tcp_server
2298 ``''''''``{
2299 ``''''''``public:
2300 ``''''''`` tcp_server(boost::asio::io_service& io_service)
2301 ``''''''`` : acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
2302 ``''''''`` {
2303 ``''''''`` start_accept();
2304 ``''''''`` }
2305
2306 ``''''''``private:
2307 ``''''''`` void start_accept()
2308 ``''''''`` {
2309 ``''''''`` tcp_connection::pointer new_connection =
2310 ``''''''`` tcp_connection::create(acceptor_.get_io_service());
2311
2312 ``''''''`` acceptor_.async_accept(new_connection->socket(),
2313 ``''''''`` boost::bind(&tcp_server::handle_accept, this, new_connection,
2314 ``''''''`` boost::asio::placeholders::error));
2315 ``''''''`` }
2316
2317 ``''''''`` void handle_accept(tcp_connection::pointer new_connection,
2318 ``''''''`` const boost::system::error_code& error)
2319 ``''''''`` {
2320 ``''''''`` if (!error)
2321 ``''''''`` {
2322 ``''''''`` new_connection->start();
2323 ``''''''`` }
2324
2325 ``''''''`` start_accept();
2326 ``''''''`` }
2327
2328 ``''''''`` tcp::acceptor acceptor_;
2329 ``''''''``};
2330
2331 ``''''''``class udp_server
2332 ``''''''``{
2333 ``''''''``public:
2334 ``''''''`` udp_server(boost::asio::io_service& io_service)
2335 ``''''''`` : socket_(io_service, udp::endpoint(udp::v4(), 13))
2336 ``''''''`` {
2337 ``''''''`` start_receive();
2338 ``''''''`` }
2339
2340 ``''''''``private:
2341 ``''''''`` void start_receive()
2342 ``''''''`` {
2343 ``''''''`` socket_.async_receive_from(
2344 ``''''''`` boost::asio::buffer(recv_buffer_), remote_endpoint_,
2345 ``''''''`` boost::bind(&udp_server::handle_receive, this,
2346 ``''''''`` boost::asio::placeholders::error));
2347 ``''''''`` }
2348
2349 ``''''''`` void handle_receive(const boost::system::error_code& error)
2350 ``''''''`` {
2351 ``''''''`` if (!error || error == boost::asio::error::message_size)
2352 ``''''''`` {
2353 ``''''''`` boost::shared_ptr<std::string> message(
2354 ``''''''`` new std::string(make_daytime_string()));
2355
2356 ``''''''`` socket_.async_send_to(boost::asio::buffer(*message), remote_endpoint_,
2357 ``''''''`` boost::bind(&udp_server::handle_send, this, message));
2358
2359 ``''''''`` start_receive();
2360 ``''''''`` }
2361 ``''''''`` }
2362
2363 ``''''''`` void handle_send(boost::shared_ptr<std::string> /*message*/)
2364 ``''''''`` {
2365 ``''''''`` }
2366
2367 ``''''''`` udp::socket socket_;
2368 ``''''''`` udp::endpoint remote_endpoint_;
2369 ``''''''`` boost::array<char, 1> recv_buffer_;
2370 ``''''''``};
2371
2372 ``''''''``int main()
2373 ``''''''``{
2374 ``''''''`` try
2375 ``''''''`` {
2376 ``''''''`` boost::asio::io_service io_service;
2377 ``''''''`` tcp_server server1(io_service);
2378 ``''''''`` udp_server server2(io_service);
2379 ``''''''`` io_service.run();
2380 ``''''''`` }
2381 ``''''''`` catch (std::exception& e)
2382 ``''''''`` {
2383 ``''''''`` std::cerr << e.what() << std::endl;
2384 ``''''''`` }
2385
2386 ``''''''`` return 0;
2387 ``''''''``}
2388
2389Return to [link boost_asio.tutorial.tutdaytime7 Daytime.7 - A combined TCP/UDP asynchronous server]
2390
2391[endsect]
2392
2393[endsect]
2394
2395
2396[endsect]