| src/examples/cpp03/timeouts/server.cpp | src/examples/cpp11/timeouts/server.cpp |
| ⋮ | ⋮ |
| 1 | // | 1 | // |
| 2 | //·server.cpp | 2 | //·server.cpp |
| 3 | //·~~~~~~~~~~ | 3 | //·~~~~~~~~~~ |
| 4 | // | 4 | // |
| 5 | //·Copyright·(c)·2003-2020·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) | 5 | //·Copyright·(c)·2003-2020·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·<algorithm> | 11 | #include·<algorithm> |
| 12 | #include·<cstdlib> | 12 | #include·<cstdlib> |
| 13 | #include·<deque> | 13 | #include·<deque> |
| 14 | #include·<iostream> | 14 | #include·<iostream> |
| | 15 | #include·<memory> |
| 15 | #include·<set> | 16 | #include·<set> |
| 16 | #include·<string> | 17 | #include·<string> |
| 17 | #include·<boost/bind/bind.hpp> | |
| 18 | #include·<boost/shared_ptr.hpp> | |
| 19 | #include·<boost/enable_shared_from_this.hpp> | |
| 20 | #include·"asio/buffer.hpp" | 18 | #include·"asio/buffer.hpp" |
| 21 | #include·"asio/io_context.hpp" | 19 | #include·"asio/io_context.hpp" |
| 22 | #include·"asio/ip/tcp.hpp" | 20 | #include·"asio/ip/tcp.hpp" |
| 23 | #include·"asio/ip/udp.hpp" | 21 | #include·"asio/ip/udp.hpp" |
| 24 | #include·"asio/read_until.hpp" | 22 | #include·"asio/read_until.hpp" |
| 25 | #include·"asio/steady_timer.hpp" | 23 | #include·"asio/steady_timer.hpp" |
| 26 | #include·"asio/write.hpp" | 24 | #include·"asio/write.hpp" |
| 27 | | 25 | |
| 28 | using·asio::steady_timer; | 26 | using·asio::steady_timer; |
| 29 | using·asio::ip::tcp; | 27 | using·asio::ip::tcp; |
| 30 | using·asio::ip::udp; | 28 | using·asio::ip::udp; |
| 31 | | 29 | |
| 32 | //---------------------------------------------------------------------- | 30 | //---------------------------------------------------------------------- |
| 33 | | 31 | |
| 34 | class·subscriber | 32 | class·subscriber |
| 35 | { | 33 | { |
| 36 | public: | 34 | public: |
| 37 | ··virtual·~subscriber()·{} | 35 | ··virtual·~subscriber()·=·default; |
| 38 | ··virtual·void·deliver(const·std::string&·msg)·=·0; | 36 | ··virtual·void·deliver(const·std::string&·msg)·=·0; |
| 39 | }; | 37 | }; |
| 40 | | 38 | |
| 41 | typedef·boost::shared_ptr<subscriber>·subscriber_ptr; | 39 | typedef·std::shared_ptr<subscriber>·subscriber_ptr; |
| 42 | | 40 | |
| 43 | //---------------------------------------------------------------------- | 41 | //---------------------------------------------------------------------- |
| 44 | | 42 | |
| 45 | class·channel | 43 | class·channel |
| 46 | { | 44 | { |
| 47 | public: | 45 | public: |
| 48 | ··void·join(subscriber_ptr·subscriber) | 46 | ··void·join(subscriber_ptr·subscriber) |
| 49 | ··{ | 47 | ··{ |
| 50 | ····subscribers_.insert(subscriber); | 48 | ····subscribers_.insert(subscriber); |
| 51 | ··} | 49 | ··} |
| 52 | | 50 | |
| 53 | ··void·leave(subscriber_ptr·subscriber) | 51 | ··void·leave(subscriber_ptr·subscriber) |
| 54 | ··{ | 52 | ··{ |
| 55 | ····subscribers_.erase(subscriber); | 53 | ····subscribers_.erase(subscriber); |
| 56 | ··} | 54 | ··} |
| 57 | | 55 | |
| 58 | ··void·deliver(const·std::string&·msg) | 56 | ··void·deliver(const·std::string&·msg) |
| 59 | ··{ | 57 | ··{ |
| 60 | ····std::for_each(subscribers_.begin(),·subscribers_.end(), | 58 | ····for·(const·auto&·s·:·subscribers_) |
| 61 | ········boost::bind(&subscriber::deliver, | 59 | ····{ |
| 62 | ··········boost::placeholders::_1,·boost::ref(msg))); | 60 | ······s->deliver(msg); |
| | 61 | ····} |
| 63 | ··} | 62 | ··} |
| 64 | | 63 | |
| 65 | private: | 64 | private: |
| 66 | ··std::set<subscriber_ptr>·subscribers_; | 65 | ··std::set<subscriber_ptr>·subscribers_; |
| 67 | }; | 66 | }; |
| 68 | | 67 | |
| 69 | //---------------------------------------------------------------------- | 68 | //---------------------------------------------------------------------- |
| 70 | | 69 | |
| 71 | // | 70 | // |
| 72 | //·This·class·manages·socket·timeouts·by·applying·the·concept·of·a·deadline. | 71 | //·This·class·manages·socket·timeouts·by·applying·the·concept·of·a·deadline. |
| 73 | //·Some·asynchronous·operations·are·given·deadlines·by·which·they·must·complete. | 72 | //·Some·asynchronous·operations·are·given·deadlines·by·which·they·must·complete. |
| 74 | //·Deadlines·are·enforced·by·two·"actors"·that·persist·for·the·lifetime·of·the | 73 | //·Deadlines·are·enforced·by·two·"actors"·that·persist·for·the·lifetime·of·the |
| 75 | //·session·object,·one·for·input·and·one·for·output: | 74 | //·session·object,·one·for·input·and·one·for·output: |
| 76 | // | 75 | // |
| 77 | //··+----------------+·····················+----------------+ | 76 | //··+----------------+······················+----------------+ |
| 78 | //··|················|·····················|················| | 77 | //··|················|······················|················| |
| 79 | //··|·check_deadline·|<---+················|·check_deadline·|<---+ | 78 | //··|·check_deadline·|<-------+·············|·check_deadline·|<-------+ |
| 80 | //··|················|····|·async_wait()···|················|····|·async_wait() | 79 | //··|················|········|·············|················|········| |
| 81 | //··+----------------+····|··on·input······+----------------+····|··on·output | 80 | //··+----------------+········|·············+----------------+········| |
| 82 | //··············|·········|··deadline··················|·········|··deadline | 81 | //···············|············|··························|············| |
| 83 | //··············+---------+····························+---------+ | 82 | //··async_wait()·|····+----------------+····async_wait()·|····+----------------+ |
| | 83 | //···on·input····|····|·····lambda·····|·····on·output···|····|·····lambda·····| |
| | 84 | //···deadline····+--->|·······in·······|·····deadline····+--->|·······in·······| |
| | 85 | //····················|·check_deadline·|······················|·check_deadline·| |
| | 86 | //····················+----------------+······················+----------------+ |
| 84 | // | 87 | // |
| 85 | //·If·either·deadline·actor·determines·that·the·corresponding·deadline·has | 88 | //·If·either·deadline·actor·determines·that·the·corresponding·deadline·has |
| 86 | //·expired,·the·socket·is·closed·and·any·outstanding·operations·are·cancelled. | 89 | //·expired,·the·socket·is·closed·and·any·outstanding·operations·are·cancelled. |
| 87 | // | 90 | // |
| 88 | //·The·input·actor·reads·messages·from·the·socket,·where·messages·are·delimited | 91 | //·The·input·actor·reads·messages·from·the·socket,·where·messages·are·delimited |
| 89 | //·by·the·newline·character: | 92 | //·by·the·newline·character: |
| 90 | // | 93 | // |
| 91 | //··+------------+ | 94 | //··+-------------+ |
| 92 | //··|············| | 95 | //··|·············| |
| 93 | //··|·start_read·|<---+ | 96 | //··|··read_line··|<----+ |
| 94 | //··|············|····| | 97 | //··|·············|·····| |
| 95 | //··+------------+····| | 98 | //··+-------------+·····| |
| 96 | //··········|·········| | 99 | //··········|···········| |
| 97 | //··async_-·|····+-------------+ | 100 | //··async_-·|····+-------------+ |
| 98 | //···read_-·|····|·············| | 101 | //···read_-·|····|···lambda····| |
| 99 | //··until()·+--->|·handle_read·| | 102 | //··until()·+--->|·····in······| |
| 100 | //···············|·············| | 103 | //···············|··read_line··| |
| 101 | //···············+-------------+ | 104 | //···············+-------------+ |
| 102 | // | 105 | // |
| 103 | //·The·deadline·for·receiving·a·complete·message·is·30·seconds.·If·a·non-empty | 106 | //·The·deadline·for·receiving·a·complete·message·is·30·seconds.·If·a·non-empty |
| 104 | //·message·is·received,·it·is·delivered·to·all·subscribers.·If·a·heartbeat·(a | 107 | //·message·is·received,·it·is·delivered·to·all·subscribers.·If·a·heartbeat·(a |
| 105 | //·message·that·consists·of·a·single·newline·character)·is·received,·a·heartbeat | 108 | //·message·that·consists·of·a·single·newline·character)·is·received,·a·heartbeat |
| 106 | //·is·enqueued·for·the·client,·provided·there·are·no·other·messages·waiting·to | 109 | //·is·enqueued·for·the·client,·provided·there·are·no·other·messages·waiting·to |
| 107 | //·be·sent. | 110 | //·be·sent. |
| 108 | // | 111 | // |
| 109 | //·The·output·actor·is·responsible·for·sending·messages·to·the·client: | 112 | //·The·output·actor·is·responsible·for·sending·messages·to·the·client: |
| 110 | // | 113 | // |
| 111 | //··+--------------+ | 114 | //··+----------------+ |
| 112 | //··|··············|<---------------------+ | 115 | //··|················|<---------------------+ |
| 113 | //··|·await_output·|······················| | 116 | //··|··await_output··|······················| |
| 114 | //··|··············|<---+·················| | 117 | //··|················|<-------+·············| |
| 115 | //··+--------------+····|·················| | 118 | //··+----------------+········|·············| |
| 116 | //······|······|········|·async_wait()····| | 119 | //····|············|··········|·············| |
| 117 | //······|······+--------+·················| | 120 | //····|····async_-·|··+----------------+····| |
| 118 | //······V·································| | 121 | //····|·····wait()·|··|·····lambda·····|····| |
| 119 | //··+-------------+···············+--------------+ | 122 | //····|············+->|·······in·······|····| |
| 120 | //··|·············|·async_write()·|··············| | 123 | //····|···············|··await_output··|····| |
| 121 | //··|·start_write·|-------------->|·handle_write·| | 124 | //····|···············+----------------+····| |
| 122 | //··|·············|···············|··············| | 125 | //····V·····································| |
| 123 | //··+-------------+···············+--------------+ | 126 | //··+--------------+···············+--------------+ |
| | 127 | //··|··············|·async_write()·|····lambda····| |
| | 128 | //··|··write_line··|-------------->|······in······| |
| | 129 | //··|··············|···············|··write_line··| |
| | 130 | //··+--------------+···············+--------------+ |
| 124 | // | 131 | // |
| 125 | //·The·output·actor·first·waits·for·an·output·message·to·be·enqueued.·It·does | 132 | //·The·output·actor·first·waits·for·an·output·message·to·be·enqueued.·It·does |
| 126 | //·this·by·using·a·steady_timer·as·an·asynchronous·condition·variable.·The | 133 | //·this·by·using·a·steady_timer·as·an·asynchronous·condition·variable.·The |
| 127 | //·steady_timer·will·be·signalled·whenever·the·output·queue·is·non-empty. | 134 | //·steady_timer·will·be·signalled·whenever·the·output·queue·is·non-empty. |
| 128 | // | 135 | // |
| 129 | //·Once·a·message·is·available,·it·is·sent·to·the·client.·The·deadline·for | 136 | //·Once·a·message·is·available,·it·is·sent·to·the·client.·The·deadline·for |
| 130 | //·sending·a·complete·message·is·30·seconds.·After·the·message·is·successfully | 137 | //·sending·a·complete·message·is·30·seconds.·After·the·message·is·successfully |
| 131 | //·sent,·the·output·actor·again·waits·for·the·output·queue·to·become·non-empty. | 138 | //·sent,·the·output·actor·again·waits·for·the·output·queue·to·become·non-empty. |
| 132 | // | 139 | // |
| 133 | class·tcp_session | 140 | class·tcp_session |
| 134 | ··:·public·subscriber, | 141 | ··:·public·subscriber, |
| 135 | ····public·boost::enable_shared_from_this<tcp_session> | 142 | ····public·std::enable_shared_from_this<tcp_session> |
| 136 | { | 143 | { |
| 137 | public: | 144 | public: |
| 138 | ··tcp_session(asio::io_context&·io_context,·channel&·ch) | 145 | ··tcp_session(tcp::socket·socket,·channel&·ch) |
| 139 | ····:·channel_(ch), | 146 | ····:·channel_(ch), |
| 140 | ······socket_(io_context), | 147 | ······socket_(std::move(socket)) |
| 141 | ······input_deadline_(io_context), | |
| 142 | ······non_empty_output_queue_(io_context), | |
| 143 | ······output_deadline_(io_context) | |
| 144 | ··{ | 148 | ··{ |
| 145 | ····input_deadline_.expires_at(steady_timer::time_point::max()); | 149 | ····input_deadline_.expires_at(steady_timer::time_point::max()); |
| 146 | ····output_deadline_.expires_at(steady_timer::time_point::max()); | 150 | ····output_deadline_.expires_at(steady_timer::time_point::max()); |
| 147 | | 151 | |
| 148 | ····//·The·non_empty_output_queue_·steady_timer·is·set·to·the·maximum·time | 152 | ····//·The·non_empty_output_queue_·steady_timer·is·set·to·the·maximum·time |
| 149 | ····//·point·whenever·the·output·queue·is·empty.·This·ensures·that·the·output | 153 | ····//·point·whenever·the·output·queue·is·empty.·This·ensures·that·the·output |
| 150 | ····//·actor·stays·asleep·until·a·message·is·put·into·the·queue. | 154 | ····//·actor·stays·asleep·until·a·message·is·put·into·the·queue. |
| 151 | ····non_empty_output_queue_.expires_at(steady_timer::time_point::max()); | 155 | ····non_empty_output_queue_.expires_at(steady_timer::time_point::max()); |
| 152 | ··} | 156 | ··} |
| 153 | | 157 | |
| 154 | ··tcp::socket&·socket() | |
| 155 | ··{ | |
| 156 | ····return·socket_; | |
| 157 | ··} | |
| 158 | | |
| 159 | ··//·Called·by·the·server·object·to·initiate·the·four·actors. | 158 | ··//·Called·by·the·server·object·to·initiate·the·four·actors. |
| 160 | ··void·start() | 159 | ··void·start() |
| 161 | ··{ | 160 | ··{ |
| 162 | ····channel_.join(shared_from_this()); | 161 | ····channel_.join(shared_from_this()); |
| 163 | | 162 | |
| 164 | ····start_read(); | 163 | ····read_line(); |
| 165 | | 164 | ····check_deadline(input_deadline_); |
| 166 | ····input_deadline_.async_wait( | |
| 167 | ········boost::bind(&tcp_session::check_deadline, | |
| 168 | ········shared_from_this(),·&input_deadline_)); | |
| 169 | | 165 | |
| 170 | ····await_output(); | 166 | ····await_output(); |
| 171 | | 167 | ····check_deadline(output_deadline_); |
| 172 | ····output_deadline_.async_wait( | |
| 173 | ········boost::bind(&tcp_session::check_deadline, | |
| 174 | ········shared_from_this(),·&output_deadline_)); | |
| 175 | ··} | 168 | ··} |
| 176 | | 169 | |
| 177 | private: | 170 | private: |
| 178 | ··void·stop() | 171 | ··void·stop() |
| 179 | ··{ | 172 | ··{ |
| 180 | ····channel_.leave(shared_from_this()); | 173 | ····channel_.leave(shared_from_this()); |
| 181 | | 174 | |
| 182 | ····asio::error_code·ignored_ec; | 175 | ····std::error_code·ignored_error; |
| 183 | ····socket_.close(ignored_ec); | 176 | ····socket_.close(ignored_error); |
| 184 | ····input_deadline_.cancel(); | 177 | ····input_deadline_.cancel(); |
| 185 | ····non_empty_output_queue_.cancel(); | 178 | ····non_empty_output_queue_.cancel(); |
| 186 | ····output_deadline_.cancel(); | 179 | ····output_deadline_.cancel(); |
| 187 | ··} | 180 | ··} |
| 188 | | 181 | |
| 189 | ··bool·stopped()·const | 182 | ··bool·stopped()·const |
| 190 | ··{ | 183 | ··{ |
| 191 | ····return·!socket_.is_open(); | 184 | ····return·!socket_.is_open(); |
| 192 | ··} | 185 | ··} |
| 193 | | 186 | |
| 194 | ··void·deliver(const·std::string&·msg) | 187 | ··void·deliver(const·std::string&·msg)·override |
| 195 | ··{ | 188 | ··{ |
| 196 | ····output_queue_.push_back(msg·+·"\n"); | 189 | ····output_queue_.push_back(msg·+·"\n"); |
| 197 | | 190 | |
| 198 | ····//·Signal·that·the·output·queue·contains·messages.·Modifying·the·expiry | 191 | ····//·Signal·that·the·output·queue·contains·messages.·Modifying·the·expiry |
| 199 | ····//·will·wake·the·output·actor,·if·it·is·waiting·on·the·timer. | 192 | ····//·will·wake·the·output·actor,·if·it·is·waiting·on·the·timer. |
| 200 | ····non_empty_output_queue_.expires_at(steady_timer::time_point::min()); | 193 | ····non_empty_output_queue_.expires_at(steady_timer::time_point::min()); |
| 201 | ··} | 194 | ··} |
| 202 | | 195 | |
| 203 | ··void·start_read() | 196 | ··void·read_line() |
| 204 | ··{ | 197 | ··{ |
| 205 | ····//·Set·a·deadline·for·the·read·operation. | 198 | ····//·Set·a·deadline·for·the·read·operation. |
| 206 | ····input_deadline_.expires_after(asio::chrono::seconds(30)); | 199 | ····input_deadline_.expires_after(std::chrono::seconds(30)); |
| 207 | | 200 | |
| 208 | ····//·Start·an·asynchronous·operation·to·read·a·newline-delimited·message. | 201 | ····//·Start·an·asynchronous·operation·to·read·a·newline-delimited·message. |
| | 202 | ····auto·self(shared_from_this()); |
| 209 | ····asio::async_read_until(socket_, | 203 | ····asio::async_read_until(socket_, |
| 210 | ········asio::dynamic_buffer(input_buffer_),·'\n', | 204 | ········asio::dynamic_buffer(input_buffer_),·'\n', |
| 211 | ········boost::bind(&tcp_session::handle_read,·shared_from_this(), | 205 | ········[this,·self](const·std::error_code&·error,·std::size_t·n) |
| 212 | ··········boost::placeholders::_1,·boost::placeholders::_2)); | |
| 213 | ··} | |
| 214 | | |
| 215 | ··void·handle_read(const·asio::error_code&·ec,·std::size_t·n) | |
| 216 | ··{ | |
| 217 | ····if·(stopped()) | |
| 218 | ······return; | |
| 219 | | |
| 220 | ····if·(!ec) | |
| 221 | ····{ | |
| 222 | ······//·Extract·the·newline-delimited·message·from·the·buffer. | |
| 223 | ······std::string·msg(input_buffer_.substr(0,·n·-·1)); | |
| 224 | ······input_buffer_.erase(0,·n); | |
| 225 | | |
| 226 | ······if·(!msg.empty()) | |
| 227 | ······{ | |
| 228 | ········channel_.deliver(msg); | |
| 229 | ······} | |
| 230 | ······else | |
| 231 | ······{ | |
| 232 | ········//·We·received·a·heartbeat·message·from·the·client.·If·there's·nothing | |
| 233 | ········//·else·being·sent·or·ready·to·be·sent,·send·a·heartbeat·right·back. | |
| 234 | ········if·(output_queue_.empty()) | |
| 235 | ········{ | 206 | ········{ |
| 236 | ··········output_queue_.push_back("\n"); | 207 | ··········//·Check·if·the·session·was·stopped·while·the·operation·was·pending. |
| 237 | | 208 | ··········if·(stopped()) |
| 238 | ··········//·Signal·that·the·output·queue·contains·messages.·Modifying·the | 209 | ············return; |
| 239 | ··········//·expiry·will·wake·the·output·actor,·if·it·is·waiting·on·the·timer. | 210 | |
| 240 | ··········non_empty_output_queue_.expires_at(steady_timer::time_point::min()); | 211 | ··········if·(!error) |
| 241 | ········} | 212 | ··········{ |
| 242 | ······} | 213 | ············//·Extract·the·newline-delimited·message·from·the·buffer. |
| 243 | | 214 | ············std::string·msg(input_buffer_.substr(0,·n·-·1)); |
| 244 | ······start_read(); | 215 | ············input_buffer_.erase(0,·n); |
| 245 | ····} | 216 | |
| 246 | ····else | 217 | ············if·(!msg.empty()) |
| 247 | ····{ | 218 | ············{ |
| 248 | ······stop(); | 219 | ··············channel_.deliver(msg); |
| 249 | ····} | 220 | ············} |
| | 221 | ············else |
| | 222 | ············{ |
| | 223 | |
| | 224 | ··············//·We·received·a·heartbeat·message·from·the·client.·If·there's |
| | 225 | ··············//·nothing·else·being·sent·or·ready·to·be·sent,·send·a·heartbeat |
| | 226 | ··············//·right·back. |
| | 227 | ··············if·(output_queue_.empty()) |
| | 228 | ··············{ |
| | 229 | ················output_queue_.push_back("\n"); |
| | 230 | |
| | 231 | ················//·Signal·that·the·output·queue·contains·messages.·Modifying |
| | 232 | ················//·the·expiry·will·wake·the·output·actor,·if·it·is·waiting·on |
| | 233 | ················//·the·timer. |
| | 234 | ················non_empty_output_queue_.expires_at( |
| | 235 | ····················steady_timer::time_point::min()); |
| | 236 | ··············} |
| | 237 | ············} |
| | 238 | |
| | 239 | ············read_line(); |
| | 240 | ··········} |
| | 241 | ··········else |
| | 242 | ··········{ |
| | 243 | ············stop(); |
| | 244 | ··········} |
| | 245 | ········}); |
| 250 | ··} | 246 | ··} |
| 251 | | 247 | |
| 252 | ··void·await_output() | 248 | ··void·await_output() |
| 253 | ··{ | 249 | ··{ |
| 254 | ····if·(stopped()) | 250 | ····auto·self(shared_from_this()); |
| 255 | ······return; | 251 | ····non_empty_output_queue_.async_wait( |
| 256 | | 252 | ········[this,·self](const·std::error_code&·/*error*/) |
| 257 | ····if·(output_queue_.empty()) | 253 | ········{ |
| 258 | ····{ | 254 | ··········//·Check·if·the·session·was·stopped·while·the·operation·was·pending. |
| 259 | ······//·There·are·no·messages·that·are·ready·to·be·sent.·The·actor·goes·to | 255 | ··········if·(stopped()) |
| 260 | ······//·sleep·by·waiting·on·the·non_empty_output_queue_·timer.·When·a·new | 256 | ············return; |
| 261 | ······//·message·is·added,·the·timer·will·be·modified·and·the·actor·will·wake. | 257 | |
| 262 | ······non_empty_output_queue_.expires_at(steady_timer::time_point::max()); | 258 | ··········if·(output_queue_.empty()) |
| 263 | ······non_empty_output_queue_.async_wait( | 259 | ··········{ |
| 264 | ··········boost::bind(&tcp_session::await_output,·shared_from_this())); | 260 | ············//·There·are·no·messages·that·are·ready·to·be·sent.·The·actor·goes |
| 265 | ····} | 261 | ············//·to·sleep·by·waiting·on·the·non_empty_output_queue_·timer.·When·a |
| 266 | ····else | 262 | ············//·new·message·is·added,·the·timer·will·be·modified·and·the·actor |
| 267 | ····{ | 263 | ············//·will·wake. |
| 268 | ······start_write(); | 264 | ············non_empty_output_queue_.expires_at(steady_timer::time_point::max()); |
| 269 | ····} | 265 | ············await_output(); |
| | 266 | ··········} |
| | 267 | ··········else |
| | 268 | ··········{ |
| | 269 | ············write_line(); |
| | 270 | ··········} |
| | 271 | ········}); |
| 270 | ··} | 272 | ··} |
| 271 | | 273 | |
| 272 | ··void·start_write() | 274 | ··void·write_line() |
| 273 | ··{ | 275 | ··{ |
| 274 | ····//·Set·a·deadline·for·the·write·operation. | 276 | ····//·Set·a·deadline·for·the·write·operation. |
| 275 | ····output_deadline_.expires_after(asio::chrono::seconds(30)); | 277 | ····output_deadline_.expires_after(std::chrono::seconds(30)); |
| 276 | | 278 | |
| 277 | ····//·Start·an·asynchronous·operation·to·send·a·message. | 279 | ····//·Start·an·asynchronous·operation·to·send·a·message. |
| | 280 | ····auto·self(shared_from_this()); |
| 278 | ····asio::async_write(socket_, | 281 | ····asio::async_write(socket_, |
| 279 | ········asio::buffer(output_queue_.front()), | 282 | ········asio::buffer(output_queue_.front()), |
| 280 | ········boost::bind(&tcp_session::handle_write, | 283 | ········[this,·self](const·std::error_code&·error,·std::size_t·/*n*/) |
| 281 | ··········shared_from_this(),·boost::placeholders::_1)); | 284 | ········{ |
| 282 | ··} | 285 | ··········//·Check·if·the·session·was·stopped·while·the·operation·was·pending. |
| 283 | | 286 | ··········if·(stopped()) |
| 284 | ··void·handle_write(const·asio::error_code&·ec) | 287 | ············return; |
| 285 | ··{ | 288 | |
| 286 | ····if·(stopped()) | 289 | ··········if·(!error) |
| 287 | ······return; | 290 | ··········{ |
| 288 | | 291 | ············output_queue_.pop_front(); |
| 289 | ····if·(!ec) | 292 | |
| 290 | ····{ | 293 | ············await_output(); |
| 291 | ······output_queue_.pop_front(); | 294 | ··········} |
| 292 | | 295 | ··········else |
| 293 | ······await_output(); | 296 | ··········{ |
| 294 | ····} | 297 | ············stop(); |
| 295 | ····else | 298 | ··········} |
| 296 | ····{ | 299 | ········}); |
| 297 | ······stop(); | 300 | ··} |
| 298 | ····} | 301 | |
| 299 | ··} | 302 | ··void·check_deadline(steady_timer&·deadline) |
| 300 | | 303 | ··{ |
| 301 | ··void·check_deadline(steady_timer*·deadline) | 304 | ····auto·self(shared_from_this()); |
| 302 | ··{ | 305 | ····deadline.async_wait( |
| 303 | ····if·(stopped()) | 306 | ········[this,·self,·&deadline](const·std::error_code&·/*error*/) |
| 304 | ······return; | 307 | ········{ |
| 305 | | 308 | ··········//·Check·if·the·session·was·stopped·while·the·operation·was·pending. |
| 306 | ····//·Check·whether·the·deadline·has·passed.·We·compare·the·deadline·against | 309 | ··········if·(stopped()) |
| 307 | ····//·the·current·time·since·a·new·asynchronous·operation·may·have·moved·the | 310 | ············return; |
| 308 | ····//·deadline·before·this·actor·had·a·chance·to·run. | 311 | |
| 309 | ····if·(deadline->expiry()·<=·steady_timer::clock_type::now()) | 312 | ··········//·Check·whether·the·deadline·has·passed.·We·compare·the·deadline |
| 310 | ····{ | 313 | ··········//·against·the·current·time·since·a·new·asynchronous·operation·may |
| 311 | ······//·The·deadline·has·passed.·Stop·the·session.·The·other·actors·will | 314 | ··········//·have·moved·the·deadline·before·this·actor·had·a·chance·to·run. |
| 312 | ······//·terminate·as·soon·as·possible. | 315 | ··········if·(deadline.expiry()·<=·steady_timer::clock_type::now()) |
| 313 | ······stop(); | 316 | ··········{ |
| 314 | ····} | 317 | ············//·The·deadline·has·passed.·Stop·the·session.·The·other·actors·will |
| 315 | ····else | 318 | ············//·terminate·as·soon·as·possible. |
| 316 | ····{ | 319 | ············stop(); |
| 317 | ······//·Put·the·actor·back·to·sleep. | 320 | ··········} |
| 318 | ······deadline->async_wait( | 321 | ··········else |
| 319 | ··········boost::bind(&tcp_session::check_deadline, | 322 | ··········{ |
| 320 | ··········shared_from_this(),·deadline)); | 323 | ············//·Put·the·actor·back·to·sleep. |
| 321 | ····} | 324 | ············check_deadline(deadline); |
| | 325 | ··········} |
| | 326 | ········}); |
| 322 | ··} | 327 | ··} |
| 323 | | 328 | |
| 324 | ··channel&·channel_; | 329 | ··channel&·channel_; |
| 325 | ··tcp::socket·socket_; | 330 | ··tcp::socket·socket_; |
| 326 | ··std::string·input_buffer_; | 331 | ··std::string·input_buffer_; |
| 327 | ··steady_timer·input_deadline_; | 332 | ··steady_timer·input_deadline_{socket_.get_executor()}; |
| 328 | ··std::deque<std::string>·output_queue_; | 333 | ··std::deque<std::string>·output_queue_; |
| 329 | ··steady_timer·non_empty_output_queue_; | 334 | ··steady_timer·non_empty_output_queue_{socket_.get_executor()}; |
| 330 | ··steady_timer·output_deadline_; | 335 | ··steady_timer·output_deadline_{socket_.get_executor()}; |
| 331 | }; | 336 | }; |
| 332 | | 337 | |
| 333 | typedef·boost::shared_ptr<tcp_session>·tcp_session_ptr; | 338 | typedef·std::shared_ptr<tcp_session>·tcp_session_ptr; |
| 334 | | 339 | |
| 335 | //---------------------------------------------------------------------- | 340 | //---------------------------------------------------------------------- |
| 336 | | 341 | |
| 337 | class·udp_broadcaster | 342 | class·udp_broadcaster |
| 338 | ··:·public·subscriber | 343 | ··:·public·subscriber |
| 339 | { | 344 | { |
| 340 | public: | 345 | public: |
| 341 | ··udp_broadcaster(asio::io_context&·io_context, | 346 | ··udp_broadcaster(asio::io_context&·io_context, |
| 342 | ······const·udp::endpoint&·broadcast_endpoint) | 347 | ······const·udp::endpoint&·broadcast_endpoint) |
| 343 | ····:·socket_(io_context) | 348 | ····:·socket_(io_context) |
| 344 | ··{ | 349 | ··{ |
| 345 | ····socket_.connect(broadcast_endpoint); | 350 | ····socket_.connect(broadcast_endpoint); |
| 346 | ····socket_.set_option(udp::socket::broadcast(true)); | 351 | ····socket_.set_option(udp::socket::broadcast(true)); |
| 347 | ··} | 352 | ··} |
| 348 | | 353 | |
| 349 | private: | 354 | private: |
| 350 | ··void·deliver(const·std::string&·msg) | 355 | ··void·deliver(const·std::string&·msg) |
| 351 | ··{ | 356 | ··{ |
| 352 | ····asio::error_code·ignored_ec; | 357 | ····std::error_code·ignored_error; |
| 353 | ····socket_.send(asio::buffer(msg),·0,·ignored_ec); | 358 | ····socket_.send(asio::buffer(msg),·0,·ignored_error); |
| 354 | ··} | 359 | ··} |
| 355 | | 360 | |
| 356 | ··udp::socket·socket_; | 361 | ··udp::socket·socket_; |
| 357 | }; | 362 | }; |
| 358 | | 363 | |
| 359 | //---------------------------------------------------------------------- | 364 | //---------------------------------------------------------------------- |
| 360 | | 365 | |
| 361 | class·server | 366 | class·server |
| 362 | { | 367 | { |
| 363 | public: | 368 | public: |
| 364 | ··server(asio::io_context&·io_context, | 369 | ··server(asio::io_context&·io_context, |
| 365 | ······const·tcp::endpoint&·listen_endpoint, | 370 | ······const·tcp::endpoint&·listen_endpoint, |
| 366 | ······const·udp::endpoint&·broadcast_endpoint) | 371 | ······const·udp::endpoint&·broadcast_endpoint) |
| 367 | ····:·io_context_(io_context), | 372 | ····:·io_context_(io_context), |
| 368 | ······acceptor_(io_context,·listen_endpoint) | 373 | ······acceptor_(io_context,·listen_endpoint) |
| 369 | ··{ | 374 | ··{ |
| 370 | ····subscriber_ptr·bc(new·udp_broadcaster(io_context_,·broadcast_endpoint)); | 375 | ····channel_.join( |
| 371 | ····channel_.join(bc); | 376 | ········std::make_shared<udp_broadcaster>( |
| | 377 | ··········io_context_,·broadcast_endpoint)); |
| 372 | | 378 | |
| 373 | ····start_accept(); | 379 | ····accept(); |
| 374 | ··} | 380 | ··} |
| 375 | | 381 | |
| 376 | ··void·start_accept() | 382 | private: |
| 377 | ··{ | 383 | ··void·accept() |
| 378 | ····tcp_session_ptr·new_session(new·tcp_session(io_context_,·channel_)); | |
| 379 | | |
| 380 | ····acceptor_.async_accept(new_session->socket(), | |
| 381 | ········boost::bind(&server::handle_accept, | |
| 382 | ··········this,·new_session,·boost::placeholders::_1)); | |
| 383 | ··} | |
| 384 | | |
| 385 | ··void·handle_accept(tcp_session_ptr·session, | |
| 386 | ······const·asio::error_code&·ec) | |
| 387 | ··{ | 384 | ··{ |
| 388 | ····if·(!ec) | 385 | ····acceptor_.async_accept( |
| 389 | ····{ | 386 | ········[this](const·std::error_code&·error,·tcp::socket·socket) |
| 390 | ······session->start(); | 387 | ········{ |
| 391 | ····} | 388 | ··········if·(!error) |
| | 389 | ··········{ |
| | 390 | ············std::make_shared<tcp_session>(std::move(socket),·channel_)->start(); |
| | 391 | ··········} |
| 392 | | 392 | |
| 393 | ····start_accept(); | 393 | ··········accept(); |
| | 394 | ········}); |
| 394 | ··} | 395 | ··} |
| 395 | | 396 | |
| 396 | private: | |
| 397 | ··asio::io_context&·io_context_; | 397 | ··asio::io_context&·io_context_; |
| 398 | ··tcp::acceptor·acceptor_; | 398 | ··tcp::acceptor·acceptor_; |
| 399 | ··channel·channel_; | 399 | ··channel·channel_; |
| 400 | }; | 400 | }; |
| 401 | | 401 | |
| 402 | //---------------------------------------------------------------------- | 402 | //---------------------------------------------------------------------- |
| 403 | | 403 | |
| 404 | int·main(int·argc,·char*·argv[]) | 404 | int·main(int·argc,·char*·argv[]) |
| 405 | { | 405 | { |
| 406 | ··try | 406 | ··try |
| 407 | ··{ | 407 | ··{ |
| 408 | ····using·namespace·std;·//·For·atoi. | 408 | ····using·namespace·std;·//·For·atoi. |
| 409 | | 409 | |
| 410 | ····if·(argc·!=·4) | 410 | ····if·(argc·!=·4) |
| 411 | ····{ | 411 | ····{ |
| 412 | ······std::cerr·<<·"Usage:·server·<listen_port>·<bcast_address>·<bcast_port>\n"; | 412 | ······std::cerr·<<·"Usage:·server·<listen_port>·<bcast_address>·<bcast_port>\n"; |
| 413 | ······return·1; | 413 | ······return·1; |
| 414 | ····} | 414 | ····} |
| 415 | | 415 | |
| 416 | ····asio::io_context·io_context; | 416 | ····asio::io_context·io_context; |
| 417 | | 417 | |
| 418 | ····tcp::endpoint·listen_endpoint(tcp::v4(),·atoi(argv[1])); | 418 | ····tcp::endpoint·listen_endpoint(tcp::v4(),·atoi(argv[1])); |
| 419 | | 419 | |
| 420 | ····udp::endpoint·broadcast_endpoint( | 420 | ····udp::endpoint·broadcast_endpoint( |
| 421 | ········asio::ip::make_address(argv[2]),·atoi(argv[3])); | 421 | ········asio::ip::make_address(argv[2]),·atoi(argv[3])); |
| 422 | | 422 | |
| 423 | ····server·s(io_context,·listen_endpoint,·broadcast_endpoint); | 423 | ····server·s(io_context,·listen_endpoint,·broadcast_endpoint); |
| 424 | | 424 | |
| 425 | ····io_context.run(); | 425 | ····io_context.run(); |
| 426 | ··} | 426 | ··} |
| 427 | ··catch·(std::exception&·e) | 427 | ··catch·(std::exception&·e) |
| 428 | ··{ | 428 | ··{ |
| 429 | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; | 429 | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·"\n"; |
| 430 | ··} | 430 | ··} |
| 431 | | 431 | |
| 432 | ··return·0; | 432 | ··return·0; |
| 433 | } | 433 | } |