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-​2018·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​5 /​/​·​Copyright·​(c)​·​2003-​2018·​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.​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,​·_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,​·_1,​·_2)​)​;​117 ········[this](std:​:​error_code·ec,​·std:​:​size_t·length)​
118 ········​{
119 ··········​if·​(!ec)​
120 ············​write(length)​;​
121 ········​})​;​
112 ··​}122 ··​}
113 123
114 ··​void·handle_read(const·asio:​:​error_code&·ec,​·std:​:​size_t·​length)​124 ··​void·write(std:​:​size_t·​length)​
115 ··{
116 ····if·(!ec)​
117 ······start_write(length)​;​
118 ··}
119
120 ··void·start_write(std:​:​size_t·length)​
121 ··​{125 ··​{
122 ····​asio:​:​async_write(socket_,​·​asio:​:​buffer(data_,​·​length)​,​126 ····​asio:​:​async_write(socket_,​·​asio:​:​buffer(data_,​·​length)​,​
123 ········boost:​:​bind(&server:​:​handle_write,​·this,​·_1)​)​;​127 ········[this](std:​:​error_code·ec,​·std:​:​size_t·/​*length*/​)​
124 ··}128 ········{
125 129 ··········if·(!ec)​
126 ··void·handle_write(const·asio:​:​error_code&·ec)​130 ············read()​;​
127 ··{131 ········})​;​
128 ····if·(!ec)​
129 ······start_read()​;​
130 ··​}132 ··​}
131 133
132 ··​asio:​:​io_context&·​io_context_;​134 ··​asio:​:​io_context&·​io_context_;​
133 ··​asio:​:​signal_set·​signal_;​135 ··​asio:​:​signal_set·​signal_;​
134 ··​tcp:​:​acceptor·​acceptor_;​136 ··​tcp:​:​acceptor·​acceptor_;​
135 ··​tcp:​:​socket·​socket_;​137 ··​tcp:​:​socket·​socket_;​
136 ··boost:​:​array<char,​·​1024>·​data_;​138 ··​std:​:​array<char,​·​1024>·​data_;​
137 };​139 };​
138 140
139 int·​main(int·​argc,​·​char*·​argv[])​141 int·​main(int·​argc,​·​char*·​argv[])​
140 {142 {
141 ··​try143 ··​try
142 ··​{144 ··​{
143 ····​if·​(argc·​!=·​2)​145 ····​if·​(argc·​!=·​2)​
144 ····​{146 ····​{
145 ······​std:​:​cerr·​<<·​"Usage:​·​process_per_connectio​n·​<port>\n";​147 ······​std:​:​cerr·​<<·​"Usage:​·​process_per_connectio​n·​<port>\n";​
146 ······​return·​1;​148 ······​return·​1;​
147 ····​}149 ····​}
148 150
149 ····​asio:​:​io_context·​io_context;​151 ····​asio:​:​io_context·​io_context;​
150 152
151 ····​using·​namespace·​std;​·​/​/​·​For·​atoi.​153 ····​using·​namespace·​std;​·​/​/​·​For·​atoi.​
152 ····​server·​s(io_context,​·​atoi(argv[1])​)​;​154 ····​server·​s(io_context,​·​atoi(argv[1])​)​;​
153 155
154 ····​io_context.​run()​;​156 ····​io_context.​run()​;​
155 ··​}157 ··​}
156 ··​catch·​(std:​:​exception&·​e)​158 ··​catch·​(std:​:​exception&·​e)​
157 ··​{159 ··​{
158 ····​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​std:​:​endl;​160 ····​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​std:​:​endl;​
159 ··​}161 ··​}
160 }162 }