1 //
2 // echo_server.cpp
3 // ~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10
11 #include <boost/asio/io_context.hpp>
12 #include <boost/asio/ip/tcp.hpp>
13 #include <boost/asio/spawn.hpp>
14 #include <boost/asio/steady_timer.hpp>
15 #include <boost/asio/write.hpp>
16 #include <iostream>
17 #include <memory>
18
19 using boost::asio::ip::tcp;
20
21 class session : public std::enable_shared_from_this<session>
22 {
23 public:
session(boost::asio::io_context & io_context,tcp::socket socket)24 explicit session(boost::asio::io_context& io_context, tcp::socket socket)
25 : socket_(std::move(socket)),
26 timer_(io_context),
27 strand_(io_context.get_executor())
28 {
29 }
30
go()31 void go()
32 {
33 auto self(shared_from_this());
34 boost::asio::spawn(strand_,
35 [this, self](boost::asio::yield_context yield)
36 {
37 try
38 {
39 char data[128];
40 for (;;)
41 {
42 timer_.expires_from_now(std::chrono::seconds(10));
43 std::size_t n = socket_.async_read_some(boost::asio::buffer(data), yield);
44 boost::asio::async_write(socket_, boost::asio::buffer(data, n), yield);
45 }
46 }
47 catch (std::exception& e)
48 {
49 socket_.close();
50 timer_.cancel();
51 }
52 });
53
54 boost::asio::spawn(strand_,
55 [this, self](boost::asio::yield_context yield)
56 {
57 while (socket_.is_open())
58 {
59 boost::system::error_code ignored_ec;
60 timer_.async_wait(yield[ignored_ec]);
61 if (timer_.expires_from_now() <= std::chrono::seconds(0))
62 socket_.close();
63 }
64 });
65 }
66
67 private:
68 tcp::socket socket_;
69 boost::asio::steady_timer timer_;
70 boost::asio::strand<boost::asio::io_context::executor_type> strand_;
71 };
72
main(int argc,char * argv[])73 int main(int argc, char* argv[])
74 {
75 try
76 {
77 if (argc != 2)
78 {
79 std::cerr << "Usage: echo_server <port>\n";
80 return 1;
81 }
82
83 boost::asio::io_context io_context;
84
85 boost::asio::spawn(io_context,
86 [&](boost::asio::yield_context yield)
87 {
88 tcp::acceptor acceptor(io_context,
89 tcp::endpoint(tcp::v4(), std::atoi(argv[1])));
90
91 for (;;)
92 {
93 boost::system::error_code ec;
94 tcp::socket socket(io_context);
95 acceptor.async_accept(socket, yield[ec]);
96 if (!ec)
97 {
98 std::make_shared<session>(io_context, std::move(socket))->go();
99 }
100 }
101 });
102
103 io_context.run();
104 }
105 catch (std::exception& e)
106 {
107 std::cerr << "Exception: " << e.what() << "\n";
108 }
109
110 return 0;
111 }
112