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