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