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