summaryrefslogtreecommitdiff
path: root/docs/tutorials/005/page02.html
blob: 7d268e8bd0012d1befe05cb2269a9aa300f4cd97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
   <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
   <META NAME="Author" CONTENT="Billy Quinn">
   <META NAME="Description" CONTENT="A first step towards using ACE productively">
   <TITLE>ACE Tutorial 005</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">

<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER>

<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER>


<P>
<HR WIDTH="100%">

<P>We begin with <I><A HREF="server.cpp">server.cpp</A></I>.

<P>
<HR WIDTH="100%">

<P><FONT FACE="Arial,Helvetica">// $Id: server.cpp,v 1.5 1998/08/29 21:57:32
jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">/*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; We try to keep main() very
simple.&nbsp; One of the ways we do that is to push</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; much of the complicated stuff
into worker objects.&nbsp; In this case, we only</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; need to include the acceptor
header in our main source file.&nbsp; We let it</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; worry about the "real work".</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">/*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; As before, we create a simple
signal handler that will set our finished</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; flag.&nbsp; There are, of
course, more elegant ways to handle program shutdown</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; requests but that isn't really
our focus right now, so we'll just do the</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; easiest thing.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">static sig_atomic_t finished = 0;</FONT>
<BR><FONT FACE="Arial,Helvetica">extern "C" void handler (int)</FONT>
<BR><FONT FACE="Arial,Helvetica">{</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; finished = 1;</FONT>
<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">/*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; A server has to listen for
clients at a known TCP/IP port.&nbsp; The default ACE</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; port is 10002 (at least on
my system) and that's good enough for what&nbsp; we</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; want to do here.&nbsp; Obviously,
a more robust application would take a command</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; line parameter or read from
a configuration file or do some other&nbsp; clever</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; thing.&nbsp; Just like the
signal handler above, though, that's what we want to</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; focus on, so we're taking
the easy way out.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">/*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Finally, we get to main.&nbsp;
Some C++ compilers will complain loudly if your</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; function signature doesn't
match the prototype.&nbsp; Even though we're not</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; going to use the parameters,
we still&nbsp; have to specify them.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">int main (int argc, char *argv[])</FONT>
<BR><FONT FACE="Arial,Helvetica">{</FONT>
<BR><FONT FACE="Arial,Helvetica">/*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; In our earlier servers, we
used a global pointer to get to the reactor. I've</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; never really liked that idea,
so I've moved it into main() this time. When</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; we&nbsp; get to the Client_Handler
object you'll see how we manage to get a</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; pointer back to this reactor.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_Reactor reactor;</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; The acceptor
will take care of letting clients connect to us.&nbsp; It will</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; also arrange
for a&nbsp; Client_Handler to be created for each new client.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Since we're only
going to listen at one&nbsp; TCP/IP port, we only need one</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; acceptor.&nbsp;
If we wanted, though, we could create several of these&nbsp; and</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; listen at several
ports.&nbsp; (That's what we would do if we wanted to rewrite</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; inetd for&nbsp;
instance.)</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; Client_Acceptor peer_acceptor;</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Create an ACE_INET_Addr
that represents our endpoint of a connection. We</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; then open our
acceptor object with that Addr.&nbsp; Doing so tells the acceptor</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; where to listen
for connections.&nbsp; Servers generally listen at "well known"</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; addresses.&nbsp;
If not, there must be some mechanism by which the client is</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; informed of the
server's address.</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Note how ACE_ERROR_RETURN
is used if we fail to open the acceptor.&nbsp; This</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; technique is
used over and over again in our tutorials.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; if (peer_acceptor.open (ACE_INET_Addr
(PORT), &amp;reactor) == -1)</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN ((LM_ERROR,
"%p\n", "open"), -1);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Here, we know
that the open was successful.&nbsp; If it had failed, we would</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; have exited above.&nbsp;
A nice side-effect of the open() is that we're already</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; registered with
the reactor we provided it.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Install our signal
handler.&nbsp; You can actually register signal handlers</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; with the reactor.&nbsp;
You might do that when the signal handler is</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; responsible for
performing "real" work.&nbsp; Our simple flag-setter doesn't</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; justify deriving
from ACE_Event_Handler and providing a callback function</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; though.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_Sig_Action sa ((ACE_SignalHandler)
handler, SIGINT);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Like ACE_ERROR_RETURN,
the ACE_DEBUG macro gets used quite a bit.&nbsp; It's a</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; handy way to
generate uniform debug output from your program.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t)
starting up server daemon\n"));</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; This will loop
"forever" invoking the handle_events() method of our</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; reactor. handle_events()
watches for activity on any registered handlers</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; and invokes their
appropriate callbacks when necessary.&nbsp; Callback-driven</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; programming is
a big thing in ACE, you should get used to it. If the</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; signal handler
catches something, the finished flag will be set and we'll</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; exit.&nbsp; Conveniently
enough, handle_events() is also interrupted by signals</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; and will exit
back to the while() loop.&nbsp; (If you want your event loop to</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; not be interrupted
by signals, checkout the &lt;i>restart&lt;/i> flag on the</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; open() method
of ACE_Reactor if you're interested.)</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; while (!finished)</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; reactor.handle_events
();</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting
down server daemon\n"));</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; return 0;</FONT>
<BR><FONT FACE="Arial,Helvetica">}</FONT>

<P>
<HR WIDTH="100%">
<CENTER>[<A HREF="..">Tutorial
Index</A>] [<A HREF="page03.html">Continue
This Tutorial</A>]</CENTER>

</BODY>
</HTML>