| src/examples/cpp03/fork/process_per_connection.cpp | src/examples/cpp11/fork/process_per_connection.cpp | 
|---|
| ⋮ | ⋮ | 
| 1 | // | 1 | // | 
| 2 | //·process_per_connection.cpp | 2 | //·process_per_connection.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·<asio/io_context.hpp> | 11 | #include·<asio/io_context.hpp> | 
| 12 | #include·<asio/ip/tcp.hpp> | 12 | #include·<asio/ip/tcp.hpp> | 
| 13 | #include·<asio/signal_set.hpp> | 13 | #include·<asio/signal_set.hpp> | 
| 14 | #include·<asio/write.hpp> | 14 | #include·<asio/write.hpp> | 
| 15 | #include·<boost/array.hpp> |  | 
| 16 | #include·<boost/bind/bind.hpp> |  | 
| 17 | #include·<cstdlib> | 15 | #include·<cstdlib> | 
| 18 | #include·<iostream> | 16 | #include·<iostream> | 
| 19 | #include·<sys/types.h> | 17 | #include·<sys/types.h> | 
| 20 | #include·<sys/wait.h> | 18 | #include·<sys/wait.h> | 
| 21 | #include·<unistd.h> | 19 | #include·<unistd.h> | 
| 22 |  | 20 |  | 
| 23 | using·asio::ip::tcp; | 21 | using·asio::ip::tcp; | 
| 24 |  | 22 |  | 
| 25 | class·server | 23 | class·server | 
| 26 | { | 24 | { | 
| 27 | public: | 25 | public: | 
| 28 | ··server(asio::io_context&·io_context,·unsigned·short·port) | 26 | ··server(asio::io_context&·io_context,·unsigned·short·port) | 
| 29 | ····:·io_context_(io_context), | 27 | ····:·io_context_(io_context), | 
| 30 | ······signal_(io_context,·SIGCHLD), | 28 | ······signal_(io_context,·SIGCHLD), | 
| 31 | ······acceptor_(io_context,·tcp::endpoint(tcp::v4(),·port)), | 29 | ······acceptor_(io_context,·{tcp::v4(),·port}), | 
| 32 | ······socket_(io_context) | 30 | ······socket_(io_context) | 
| 33 | ··{ | 31 | ··{ | 
| 34 | ····start_signal_wait(); | 32 | ····wait_for_signal(); | 
| 35 | ····start_accept(); | 33 | ····accept(); | 
| 36 | ··} | 34 | ··} | 
| 37 |  | 35 |  | 
| 38 | private: | 36 | private: | 
| 39 | ··void·start_signal_wait() | 37 | ··void·wait_for_signal() | 
| 40 | ··{ | 38 | ··{ | 
| 41 | ····signal_.async_wait(boost::bind(&server::handle_signal_wait,·this)); | 39 | ····signal_.async_wait( | 
|  | 40 | ········[this](std::error_code·/*ec*/,·int·/*signo*/) | 
|  | 41 | ········{ | 
|  | 42 | ··········//·Only·the·parent·process·should·check·for·this·signal.·We·can | 
|  | 43 | ··········//·determine·whether·we·are·in·the·parent·by·checking·if·the·acceptor | 
|  | 44 | ··········//·is·still·open. | 
|  | 45 | ··········if·(acceptor_.is_open()) | 
|  | 46 | ··········{ | 
|  | 47 | ············//·Reap·completed·child·processes·so·that·we·don't·end·up·with | 
|  | 48 | ············//·zombies. | 
|  | 49 | ············int·status·=·0; | 
|  | 50 | ············while·(waitpid(-1,·&status,·WNOHANG)·>·0)·{} | 
|  | 51 |  | 
|  | 52 | ············wait_for_signal(); | 
|  | 53 | ··········} | 
|  | 54 | ········}); | 
|  | 55 | ··} | 
|  | 56 |  | 
|  | 57 | ··void·accept() | 
|  | 58 | ··{ | 
|  | 59 | ····acceptor_.async_accept( | 
|  | 60 | ········[this](std::error_code·ec,·tcp::socket·new_socket) | 
|  | 61 | ········{ | 
|  | 62 | ··········if·(!ec) | 
|  | 63 | ··········{ | 
|  | 64 | ············//·Take·ownership·of·the·newly·accepted·socket. | 
|  | 65 | ············socket_·=·std::move(new_socket); | 
|  | 66 |  | 
|  | 67 | ············//·Inform·the·io_context·that·we·are·about·to·fork.·The·io_context | 
|  | 68 | ············//·cleans·up·any·internal·resources,·such·as·threads,·that·may | 
|  | 69 | ············//·interfere·with·forking. | 
|  | 70 | ············io_context_.notify_fork(asio::io_context::fork_prepare); | 
|  | 71 |  | 
|  | 72 | ············if·(fork()·==·0) | 
|  | 73 | ············{ | 
|  | 74 | ··············//·Inform·the·io_context·that·the·fork·is·finished·and·that·this | 
|  | 75 | ··············//·is·the·child·process.·The·io_context·uses·this·opportunity·to | 
|  | 76 | ··············//·create·any·internal·file·descriptors·that·must·be·private·to | 
|  | 77 | ··············//·the·new·process. | 
|  | 78 | ··············io_context_.notify_fork(asio::io_context::fork_child); | 
|  | 79 |  | 
|  | 80 | ··············//·The·child·won't·be·accepting·new·connections,·so·we·can·close | 
|  | 81 | ··············//·the·acceptor.·It·remains·open·in·the·parent. | 
|  | 82 | ··············acceptor_.close(); | 
|  | 83 |  | 
|  | 84 | ··············//·The·child·process·is·not·interested·in·processing·the·SIGCHLD | 
|  | 85 | ··············//·signal. | 
|  | 86 | ··············signal_.cancel(); | 
|  | 87 |  | 
|  | 88 | ··············read(); | 
|  | 89 | ············} | 
|  | 90 | ············else | 
|  | 91 | ············{ | 
|  | 92 |  | 
|  | 93 | ··············//·Inform·the·io_context·that·the·fork·is·finished·(or·failed) | 
|  | 94 | ··············//·and·that·this·is·the·parent·process.·The·io_context·uses·this | 
|  | 95 | ··············//·opportunity·to·recreate·any·internal·resources·that·were | 
|  | 96 | ··············//·cleaned·up·during·preparation·for·the·fork. | 
|  | 97 | ··············io_context_.notify_fork(asio::io_context::fork_parent); | 
|  | 98 |  | 
|  | 99 | ··············//·The·parent·process·can·now·close·the·newly·accepted·socket.·It | 
|  | 100 | ··············//·remains·open·in·the·child. | 
|  | 101 | ··············socket_.close(); | 
|  | 102 |  | 
|  | 103 | ··············accept(); | 
|  | 104 | ············} | 
|  | 105 | ··········} | 
|  | 106 | ··········else | 
|  | 107 | ··········{ | 
|  | 108 | ············std::cerr·<<·"Accept·error:·"·<<·ec.message()·<<·std::endl; | 
|  | 109 | ············accept(); | 
|  | 110 | ··········} | 
|  | 111 | ········}); | 
| 42 | ··} | 112 | ··} | 
| 43 |  | 113 |  | 
| 44 | ··void·handle_signal_wait() | 114 | ··void·read() | 
| 45 | ··{ |  | 
| 46 | ····//·Only·the·parent·process·should·check·for·this·signal.·We·can·determine |  | 
| 47 | ····//·whether·we·are·in·the·parent·by·checking·if·the·acceptor·is·still·open. |  | 
| 48 | ····if·(acceptor_.is_open()) |  | 
| 49 | ····{ |  | 
| 50 | ······//·Reap·completed·child·processes·so·that·we·don't·end·up·with·zombies. |  | 
| 51 | ······int·status·=·0; |  | 
| 52 | ······while·(waitpid(-1,·&status,·WNOHANG)·>·0)·{} |  | 
| 53 |  |  | 
| 54 | ······start_signal_wait(); |  | 
| 55 | ····} |  | 
| 56 | ··} |  | 
| 57 |  |  | 
| 58 | ··void·start_accept() |  | 
| 59 | ··{ |  | 
| 60 | ····acceptor_.async_accept(socket_, |  | 
| 61 | ········boost::bind(&server::handle_accept,·this,·boost::placeholders::_1)); |  | 
| 62 | ··} |  | 
| 63 |  |  | 
| 64 | ··void·handle_accept(const·asio::error_code&·ec) |  | 
| 65 | ··{ |  | 
| 66 | ····if·(!ec) |  | 
| 67 | ····{ |  | 
| 68 | ······//·Inform·the·io_context·that·we·are·about·to·fork.·The·io_context·cleans |  | 
| 69 | ······//·up·any·internal·resources,·such·as·threads,·that·may·interfere·with |  | 
| 70 | ······//·forking. |  | 
| 71 | ······io_context_.notify_fork(asio::io_context::fork_prepare); |  | 
| 72 |  |  | 
| 73 | ······if·(fork()·==·0) |  | 
| 74 | ······{ |  | 
| 75 | ········//·Inform·the·io_context·that·the·fork·is·finished·and·that·this·is·the |  | 
| 76 | ········//·child·process.·The·io_context·uses·this·opportunity·to·create·any |  | 
| 77 | ········//·internal·file·descriptors·that·must·be·private·to·the·new·process. |  | 
| 78 | ········io_context_.notify_fork(asio::io_context::fork_child); |  | 
| 79 |  |  | 
| 80 | ········//·The·child·won't·be·accepting·new·connections,·so·we·can·close·the |  | 
| 81 | ········//·acceptor.·It·remains·open·in·the·parent. |  | 
| 82 | ········acceptor_.close(); |  | 
| 83 |  |  | 
| 84 | ········//·The·child·process·is·not·interested·in·processing·the·SIGCHLD·signal. |  | 
| 85 | ········signal_.cancel(); |  | 
| 86 |  |  | 
| 87 | ········start_read(); |  | 
| 88 | ······} |  | 
| 89 | ······else |  | 
| 90 | ······{ |  | 
| 91 | ········//·Inform·the·io_context·that·the·fork·is·finished·(or·failed)·and·that |  | 
| 92 | ········//·this·is·the·parent·process.·The·io_context·uses·this·opportunity·to |  | 
| 93 | ········//·recreate·any·internal·resources·that·were·cleaned·up·during |  | 
| 94 | ········//·preparation·for·the·fork. |  | 
| 95 | ········io_context_.notify_fork(asio::io_context::fork_parent); |  | 
| 96 |  |  | 
| 97 | ········socket_.close(); |  | 
| 98 | ········start_accept(); |  | 
| 99 | ······} |  | 
| 100 | ····} |  | 
| 101 | ····else |  | 
| 102 | ····{ |  | 
| 103 | ······std::cerr·<<·"Accept·error:·"·<<·ec.message()·<<·std::endl; |  | 
| 104 | ······start_accept(); |  | 
| 105 | ····} |  | 
| 106 | ··} |  | 
| 107 |  |  | 
| 108 | ··void·start_read() |  | 
| 109 | ··{ | 115 | ··{ | 
| 110 | ····socket_.async_read_some(asio::buffer(data_), | 116 | ····socket_.async_read_some(asio::buffer(data_), | 
| 111 | ········boost::bind(&server::handle_read,·this, | 117 | ········[this](std::error_code·ec,·std::size_t·length) | 
| 112 | ··········boost::placeholders::_1,·boost::placeholders::_2)); | 118 | ········{ | 
|  | 119 | ··········if·(!ec) | 
|  | 120 | ············write(length); | 
|  | 121 | ········}); | 
| 113 | ··} | 122 | ··} | 
| 114 |  | 123 |  | 
| 115 | ··void·handle_read(const·asio::error_code&·ec,·std::size_t·length) | 124 | ··void·write(std::size_t·length) | 
| 116 | ··{ |  | 
| 117 | ····if·(!ec) |  | 
| 118 | ······start_write(length); |  | 
| 119 | ··} |  | 
| 120 |  |  | 
| 121 | ··void·start_write(std::size_t·length) |  | 
| 122 | ··{ | 125 | ··{ | 
| 123 | ····asio::async_write(socket_,·asio::buffer(data_,·length), | 126 | ····asio::async_write(socket_,·asio::buffer(data_,·length), | 
| 124 | ········boost::bind(&server::handle_write,·this,·boost::placeholders::_1)); | 127 | ········[this](std::error_code·ec,·std::size_t·/*length*/) | 
| 125 | ··} | 128 | ········{ | 
| 126 |  | 129 | ··········if·(!ec) | 
| 127 | ··void·handle_write(const·asio::error_code&·ec) | 130 | ············read(); | 
| 128 | ··{ | 131 | ········}); | 
| 129 | ····if·(!ec) |  | 
| 130 | ······start_read(); |  | 
| 131 | ··} | 132 | ··} | 
| 132 |  | 133 |  | 
| 133 | ··asio::io_context&·io_context_; | 134 | ··asio::io_context&·io_context_; | 
| 134 | ··asio::signal_set·signal_; | 135 | ··asio::signal_set·signal_; | 
| 135 | ··tcp::acceptor·acceptor_; | 136 | ··tcp::acceptor·acceptor_; | 
| 136 | ··tcp::socket·socket_; | 137 | ··tcp::socket·socket_; | 
| 137 | ··boost::array<char,·1024>·data_; | 138 | ··std::array<char,·1024>·data_; | 
| 138 | }; | 139 | }; | 
| 139 |  | 140 |  | 
| 140 | int·main(int·argc,·char*·argv[]) | 141 | int·main(int·argc,·char*·argv[]) | 
| 141 | { | 142 | { | 
| 142 | ··try | 143 | ··try | 
| 143 | ··{ | 144 | ··{ | 
| 144 | ····if·(argc·!=·2) | 145 | ····if·(argc·!=·2) | 
| 145 | ····{ | 146 | ····{ | 
| 146 | ······std::cerr·<<·"Usage:·process_per_connection·<port>\n"; | 147 | ······std::cerr·<<·"Usage:·process_per_connection·<port>\n"; | 
| 147 | ······return·1; | 148 | ······return·1; | 
| 148 | ····} | 149 | ····} | 
| 149 |  | 150 |  | 
| 150 | ····asio::io_context·io_context; | 151 | ····asio::io_context·io_context; | 
| 151 |  | 152 |  | 
| 152 | ····using·namespace·std;·//·For·atoi. | 153 | ····using·namespace·std;·//·For·atoi. | 
| 153 | ····server·s(io_context,·atoi(argv[1])); | 154 | ····server·s(io_context,·atoi(argv[1])); | 
| 154 |  | 155 |  | 
| 155 | ····io_context.run(); | 156 | ····io_context.run(); | 
| 156 | ··} | 157 | ··} | 
| 157 | ··catch·(std::exception&·e) | 158 | ··catch·(std::exception&·e) | 
| 158 | ··{ | 159 | ··{ | 
| 159 | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·std::endl; | 160 | ····std::cerr·<<·"Exception:·"·<<·e.what()·<<·std::endl; | 
| 160 | ··} | 161 | ··} | 
| 161 | } | 162 | } |