src/​examples/​cpp03/​fork/​process_per_connectio​n.​cppsrc/​examples/​cpp11/​fork/​process_per_connectio​n.​cpp
1 /​/​1 /​/​
2 /​/​·​process_per_connectio​n.​cpp2 /​/​·​process_per_connectio​n.​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·​accompanying7 /​/​·​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·​server23 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_contex​t)​,​27 ····​:​·​io_context_(io_contex​t)​,​
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 ··​try143 ··​try
143 ··​{144 ··​{
144 ····​if·​(argc·​!=·​2)​145 ····​if·​(argc·​!=·​2)​
145 ····​{146 ····​{
146 ······​std:​:​cerr·​<<·​"Usage:​·​process_per_connectio​n·​<port>\n";​147 ······​std:​:​cerr·​<<·​"Usage:​·​process_per_connectio​n·​<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 }