summaryrefslogtreecommitdiff
path: root/docs/tutorials/002/page02.html
blob: d7808d58c7d4f846c64f22a550522eff1e4ba3af (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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
   <TITLE>ACE Tutorial 002</TITLE>
   <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
   <META NAME="Author" CONTENT="James CE Johnson">
   <META NAME="Description" CONTENT="A first step towards using ACE productively">
</HEAD>
<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">


<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 002<BR>
Creating a Better Server </FONT></B></P></CENTER>

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

<P>The program is actually small enough to fit into a single source file.
To make things a little easier to follow, though, I've broken it up into
three parts: main, acceptor and handler. Each is presented with line numbers
and description. Because it is a single file, you won't see <I>#include</I>
directives you may expect. Wait 'till the final page and see the whole
thing put together before you worry about things like that.</P>

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

<P>We begin by looking at the main portion program:</P>

<UL>
<PRE>1.      #include &quot;ace/Reactor.h&quot;
        
2.      ACE_Reactor * g_reactor;
        
3.      static sig_atomic_t finished = 0;
4.      extern &quot;C&quot; void handler (int) { finished = 1; }
        
5.      static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
        
6.      int main (int argc, char *argv[])
        {
7.        g_reactor = new ACE_Reactor;
        
          // Acceptor factory.
8.        Logging_Acceptor peer_acceptor;
        
9.        if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
10.         ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;open&quot;), -1);
        
11.       else if (g_reactor-&gt;register_handler (&amp;peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
12.         ACE_ERROR_RETURN ((LM_ERROR, &quot;registering service with ACE_Reactor\n&quot;), -1);
        
13.       ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
        
          // Run forever, performing logging service.
        
14.       ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) starting up server logging daemon\n&quot;));
        
          // Perform logging service until QUIT_HANDLER receives SIGINT.
15.       while ( !finished )
16.         g_reactor-&gt;handle_events ();
        
17.       ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) shutting down server logging daemon\n&quot;));
        
18.       return 0;
        }</PRE>
</UL>

<P>
<HR></P>

<OL>
<LI>The reactor is the only ACE object directly used by the main program.
We bring in it's definition here.</LI>

<LI>To keep things simple, we again have a global reactor object. This
time, however, we are keeping a pointer to it. Since C++&nbsp;isn't too
clear about initialization of global/static objects I chose to dynamically
create the object in <I>main</I> rather than having it global.</LI>

<LI><I>finished</I> is an atomic data type which we will use to tell us
the server should exit. It will be set when the program receives an <I>interrupt</I>
signal.</LI>

<LI>This &quot;C&quot; function will process the <I>interrupt</I> signal
if it is received by the program. All that it needs to do is set the <I>finished</I>
flag which our main loop will look at as an indication to exit.</LI>

<LI>The simple variable <I>PORT</I> is statically initialized to a default
value. This is where the server will listen for new client connection requests.</LI>

<LI>A typical <I>main</I> signature. Although we give ourselves access
to the command-line arguments, we won't be using them. A more robust example
might allow specifying the port number or other information via the command-line.</LI>

<LI>The global reactor pointer is now initialized. We could have just as
easily have chosen to create it on the stack and set <I>g_reactor</I> to
point to the stack variable. Either way, it gives us more control than
declaring it outside of <I>main</I>.</LI>

<LI>Now, we create the object which will accept new client requests. Unlike
the reactor, we did create this one on the stack. In the long run it really
doesn't matter since Unix is very nice about cleaning up allocated memory
when the program exits.</LI>

<LI>We now use the acceptor's <I>open</I> member function to get it up
and running. In the previous example, we passed the <I>port</I> object
to the acceptor at construction time. This time around, we're passing it
to <I>open</I> instead. Why? Well, we could have created a constructor
to accept the <I>port</I> object but we're trying to use one of ACE's tools
to create a totally generic acceptor. It turns out that that tool creates
an acceptor that requires the port passed to <I>open</I> rather than the
constructor. In the long run, this is a good thing because there is no
good way for a constructor to return a failure. Since we need to know if
the <I>SOCK_Acceptor</I> is initialized correctly, we are better off initializing
it in a function that <B>can</B> return an error code. You'll also notice
that we simply create and pass the <I>port</I> object in one step instead
of creating an intermediate variable to handle it.</LI>

<LI>We use <I>ACE_ERROR_RETURN</I> to get ourselves out if the <I>open</I>
call fails. This is a handy and consistent method for reporting nasty things.</LI>

<LI>If the <I>open</I> was successful we will get to here. It is now time
to register the acceptor with the reactor so that the acceptor's member
functions will be called when there is activity to be dealt with. Notice
that we have to pass the address of the acceptor since we created the object
on the stack instead of with <I>new</I>. Also notice that we're asking
the reactor to only respond to <I>READ</I> type events. These will be client
connection requests.</LI>

<LI>Another call to <I>ACE_ERROR_RETURN</I> if the registration failed.</LI>

<LI>An <I>ACE_Sig_Action</I> object is created and given the address of
the <I>handle</I> &quot;C&quot;&nbsp;function declared above. With that
function is associated the signal <I>SIGINT</I>. If the program receives
this signal at any time, the <I>handle</I> function will be called. This
is our way to cleanly exit the program. There is a much cleaner way to
do this by creating an object which is registered with the reactor. However,
I&nbsp;don't want to get into reactor-registered signal handlers at this
time, so we're going with the easy-out.</LI>

<LI><I>ACE_DEBUG</I> is another function like <I>ACE_ERROR_RETURN</I> that
we can use to provide consistent messages to the user. Here, we just want
to report that the program has started.</LI>

<LI>Loop forever unless <I>finished</I> gets a non-zero value. Since the
only way that can happen is by receipt of an <I>interrupt</I> signal, we
will keep running until somebody <I>kill</I>s us with that (<I>kill -SIGINT&nbsp;process-id</I>).</LI>

<LI>As always, allow the reactor to handle any events that are generated
on it's registered event handlers.</LI>

<LI>Announce our departure.</LI>

<LI>Return a successful exit value to the operating system.</LI>
</OL>

<P>We got a little sloppy by not <I>delete</I>ing the reactor we dynamically
allocated at the beginning of <I>main</I>. We really should do that for
sake of completeness and neat programming. Even if we forget though, Unix
is good about freeing up a program's memory (automatic and dynamically
allocated)&nbsp;when the program exits.</P>

<P>Now that our re-designed <I>main</I> is dealt with, we will describe
our much-improved and easier to maintain acceptor object.</P>

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

<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>] [<A HREF="page01.html">Previous
Page</A>] [<A HREF="page03.html">Continue This Tutorial</A>] </P></CENTER>

</BODY>
</HTML>