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 }