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 }