| 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-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/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 | } |