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