• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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