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-​2023·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​5 /​/​·​Copyright·​(c)​·​2003-​2023·​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 ·​·​·​·​·​·​·​·​})​;​
42 ·​·​}55 ·​·​}
43 56
44 ·​·​void·​handle_signal_wait()​57 ·​·​void·​accept()​
45 ·​·​{58 ·​·​{
46 ·​·​·​·​/​/​·​Only·​the·​parent·​process·​should·​check·​for·​this·​signal.​·​We·​can·​determine59 ·​·​·​·​acceptor_.​async_accept(
47 ·​·​·​·​/​/​·​whether·​we·​are·​in·​the·​parent·​by·​checking·​if·​the·​acceptor·​is·​still·​open.​60 ·​·​·​·​·​·​·​·​[this](std:​:​error_code·​ec,​·​tcp:​:​socket·​new_socket)​
48 ·​·​·​·​if·​(acceptor_.​is_open()​)​61 ·​·​·​·​·​·​·​·​{
49 ·​·​·​·​{62 ·​·​·​·​·​·​·​·​·​·​if·​(!ec)​
50 ·​·​·​·​·​·​/​/​·​Reap·​completed·​child·​processes·​so·​that·​we·​don't·​end·​up·​with·​zombies.​63 ·​·​·​·​·​·​·​·​·​·​{
51 ·​·​·​·​·​·​int·​status·​=·​0;​64 ·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​Take·​ownership·​of·​the·​newly·​accepted·​socket.​
52 ·​·​·​·​·​·​while·​(waitpid(-​1,​·​&status,​·​WNOHANG)​·​>·​0)​·​{}65 ·​·​·​·​·​·​·​·​·​·​·​·​socket_·​=·​std:​:​move(new_socket)​;​
53 66
54 ·​·​·​·​·​·​start_signal_wait()​;​67 ·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​Inform·​the·​io_context·​that·​we·​are·​about·​to·​fork.​·​The·​io_context
55 ·​·​·​·​}68 ·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​cleans·​up·​any·​internal·​resources,​·​such·​as·​threads,​·​that·​may
56 ·​·​}69 ·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​interfere·​with·​forking.​
70 ·​·​·​·​·​·​·​·​·​·​·​·​io_context_.​notify_fork(asio:​:​io_context:​:​fork_prepare)​;​
57 71
58 ·​·​void·​start_accept()​72 ·​·​·​·​·​·​·​·​·​·​·​·​if·​(fork()​·​==·​0)​
59 ·​·​{73 ·​·​·​·​·​·​·​·​·​·​·​·​{
60 ·​·​·​·​acceptor_.​async_accept(socket_,​74 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​Inform·​the·​io_context·​that·​the·​fork·​is·​finished·​and·​that·​this
61 ·​·​·​·​·​·​·​·​boost:​:​bind(&server:​:​handle_accept,​·​this,​·​boost:​:​placeholders:​:​_1)​)​;​75 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​is·​the·​child·​process.​·​The·​io_context·​uses·​this·​opportunity·​to
62 ·​·​}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)​;​
63 79
64 ·​·​void·​handle_accept(const·​asio:​:​error_code&·​ec)​80 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​The·​child·​won't·​be·​accepting·​new·​connections,​·​so·​we·​can·​close
65 ·​·​{81 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​the·​acceptor.​·​It·​remains·​open·​in·​the·​parent.​
66 ·​·​·​·​if·​(!ec)​82 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​acceptor_.​close()​;​
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 83
73 ·​·​·​·​·​·​if·​(fork()​·​==·​0)​84 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​The·​child·​process·​is·​not·​interested·​in·​processing·​the·​SIGCHLD
74 ·​·​·​·​·​·​{85 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​signal.​
75 ·​·​·​·​·​·​·​·​/​/​·​Inform·​the·​io_context·​that·​the·​fork·​is·​finished·​and·​that·​this·​is·​the86 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​signal_.​cancel()​;​
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 87
80 ·​·​·​·​·​·​·​·​/​/​·​The·​child·​won't·​be·​accepting·​new·​connections,​·​so·​we·​can·​close·​the88 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​read()​;​
81 ·​·​·​·​·​·​·​·​/​/​·​acceptor.​·​It·​remains·​open·​in·​the·​parent.​89 ·​·​·​·​·​·​·​·​·​·​·​·​}
82 ·​·​·​·​·​·​·​·​acceptor_.​close()​;​90 ·​·​·​·​·​·​·​·​·​·​·​·​else
91 ·​·​·​·​·​·​·​·​·​·​·​·​{
83 92
84 ·​·​·​·​·​·​·​·​/​/​·​The·​child·​process·​is·​not·​interested·​in·​processing·​the·​SIGCHLD·​signal.​93 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​Inform·​the·​io_context·​that·​the·​fork·​is·​finished·​(or·​failed)​
85 ·​·​·​·​·​·​·​·​signal_.​cancel()​;​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)​;​
86 98
87 ·​·​·​·​·​·​·​·​start_read()​;​99 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​The·​parent·​process·​can·​now·​close·​the·​newly·​accepted·​socket.​·​It
88 ·​·​·​·​·​·​}100 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​/​/​·​remains·​open·​in·​the·​child.​
89 ·​·​·​·​·​·​else101 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​socket_.​close()​;​
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 102
97 ·​·​·​·​·​·​·​·​socket_.​close()​;​103 ·​·​·​·​·​·​·​·​·​·​·​·​·​·​accept()​;​
98 ·​·​·​·​·​·​·​·​start_accept()​;​104 ·​·​·​·​·​·​·​·​·​·​·​·​}
99 ·​·​·​·​·​·​}105 ·​·​·​·​·​·​·​·​·​·​}
100 ·​·​·​·​}106 ·​·​·​·​·​·​·​·​·​·​else
101 ·​·​·​·​else107 ·​·​·​·​·​·​·​·​·​·​{
102 ·​·​·​·​{108 ·​·​·​·​·​·​·​·​·​·​·​·​std:​:​cerr·​<<·​"Accept·​error:​·​"·​<<·​ec.​message()​·​<<·​std:​:​endl;​
103 ·​·​·​·​·​·​std:​:​cerr·​<<·​"Accept·​error:​·​"·​<<·​ec.​message()​·​<<·​std:​:​endl;​109 ·​·​·​·​·​·​·​·​·​·​·​·​accept()​;​
104 ·​·​·​·​·​·​start_accept()​;​110 ·​·​·​·​·​·​·​·​·​·​}
105 ·​·​·​·​}111 ·​·​·​·​·​·​·​·​})​;​
106 ·​·​}112 ·​·​}
107 113
108 ·​·​void·​start_read()​114 ·​·​void·​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 ·​·​{125 ·​·​{
117 ·​·​·​·​if·​(!ec)​
118 ·​·​·​·​·​·​start_write(length)​;​
119 ·​·​}
120
121 ·​·​void·​start_write(std:​:​size_t·​length)​
122 ·​·​{
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*/​)​
128 ·​·​·​·​·​·​·​·​{
129 ·​·​·​·​·​·​·​·​·​·​if·​(!ec)​
130 ·​·​·​·​·​·​·​·​·​·​·​·​read()​;​
131 ·​·​·​·​·​·​·​·​})​;​
125 ·​·​}132 ·​·​}
126 133
127 ·​·​void·​handle_write(const·​asio:​:​error_code&·​ec)​
128 ·​·​{
129 ·​·​·​·​if·​(!ec)​
130 ·​·​·​·​·​·​start_read()​;​
131 ·​·​}
132
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 }