summaryrefslogtreecommitdiff
path: root/docs/tutorials/001/page03.html
blob: 73a2a9776f18d0ac494348ad35f91cc279eb5517 (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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<!-- $Id$ -->
<HTML>
<HEAD>
   <TITLE>ACE Tutorial 001</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 001<BR>
A Beginners Guide to Using the ACE&nbsp;Toolkit</FONT></B></P></CENTER>

<hr>
<P>Now we begin to look at the <A HREF="acceptor.h">acceptor</A> object.

<P>
Kirthika has this analogy:
<P>
<UL>
Consider an office:
<P>
Reactor: Receptionist
<P>
Event_Handlers: various Departments catering to specific needs.
<P>
SERVER_PORT: door
<P>
Acceptor: Doorkeeper
<P>
Thus when a needy person (client) enters the open door (port)
maintained by the doorkeeper (acceptor waiting for connection
request), the receptionist(reactor) directs the person towards the
appropriate section (event_handler) which would cater to his needs.
</UL>
<P>
<HR>
<PRE>
<font color=red>// $Id$</font>

<font color=blue>#ifndef</font> <font color=purple>_CLIENT_ACCEPTOR_H</font>
<font color=blue>#define</font> <font color=purple>_CLIENT_ACCEPTOR_H</font>

<font color=red>/* A SOCK_Acceptor knows how to accept socket connections.  We'll use
  one of those at the heart of our Logging_Acceptor.  */</font>
<font color=blue>#include</font> "<A HREF="../../../ace/SOCK_Acceptor.h">ace/SOCK_Acceptor.h</A>"

<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>)
<font color=blue># pragma</font> <font color=purple>once</font>
<font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font>

<font color=red>/* An Event_Handler is what you register with ACE_Reactor.  When
  events occur, the reactor will callback on the Event_Handler.  More
  on that in a few lines.  */</font>
<font color=blue>#include</font> "<A HREF="../../../ace/Event_Handler.h">ace/Event_Handler.h</A>"

<font color=red>/* When a client connects, we'll create a Logging_Handler to deal with
  the connection.  Here, we bring in that declaration.  */</font>
<font color=blue>#include</font> "<font color=green>logger.h</font>"

<font color=red>/* Our Logging_Acceptor is derived from ACE_Event_Handler.  That lets
  the reactor treat our acceptor just like every other handler.  */</font>
class Logging_Acceptor : public ACE_Event_Handler
{
public:

  <font color=red>/* For this simple case we won't bother with either constructor or
    destructor.  In a real application you would certainly have them.  */</font>

  <font color=red>/* Here's the open() method we called from main().  We have two
    things to accomplish here: (1) Open the acceptor so that we can
    hear client requests and (2) register ourselves with the reactor
    so that we can respond to those requests.  */</font>
  int open (const ACE_INET_Addr &addr,
            ACE_Reactor *reactor)
  {
    <font color=red>/* Perform the open() on the acceptor.  We pass through the
      address at which main() wants us to listen.  The second
      parameter tells the acceptor it is OK to reuse the address.
      This is necessary sometimes to get around closed connections
      that haven't timed out.  */</font>
    if (this->peer_acceptor_.open (addr, 1) == -1)
      return -1;

    <font color=red>/* Remember the reactor we're using.  We'll need it later when we
      create a client connection handler.  */</font>
    reactor_ = reactor;

    <font color=red>/* Now we can register with the reactor we were given.  Since the
      reactor pointer is global, we could have just used that but it's
      gross enough already.  Notice that we can pass 'this' right into
      the registration since we're derived from ACE_Event_Handler.  We
      also provide ACCEPT_MASK to tell the reactor that we want to
      know about accept requests from clients.  */</font>
    return reactor->register_handler (this,
                                      <font color=#008888>ACE_Event_Handler::ACCEPT_MASK</font>);
  }

private:

  <font color=red>/* To provide multi-OS abstraction, ACE uses the concept of
    "<font color=green>handles</font>" for connection endpoints.  In Unix, this is a
    traditional file descriptor (or integer).  On other OS's, it may
    be something else.  The reactor will need to get the handle (file
    descriptor) to satisfy it's own internal needs.  Our relevant
    handle is the handle of the acceptor object, so that's what we
    provide.  */</font>
  ACE_HANDLE get_handle (void) const
  {
    return this->peer_acceptor_.get_handle ();
  }

  <font color=red>/* When an accept request arrives, the reactor will invoke the
    handle_input() callback.  This is where we deal with the
    connection request.  */</font>
  virtual int handle_input (ACE_HANDLE handle)
  {
    <font color=red>/* The handle provided to us by the reactor is the one that
      triggered our up-call.  In some advanced situations, you might
      actually register a single handler for multiple connections.
      The _handle parameter is a way to sort 'em out.  Since we don't
      use that here, we simply ignore the parameter with the
      ACE_UNUSED_ARG() macro.  */</font>
    ACE_UNUSED_ARG (handle);

    Logging_Handler *svc_handler;

    <font color=red>/* In response to the connection request, we create a new
      Logging_Handler.  This new object will be used to interact with
      the client until it disconnects.  Note how we use the
      ACE_NEW_RETURN macro, which returns -1 if operator new fails. */</font>
    ACE_NEW_RETURN (svc_handler,
                    Logging_Handler,
                    -1);

    <font color=red>/* To complete the connection, we invoke the accept() method call
      on the acceptor object and provide it with the connection
      handler instance.  This transfers "<font color=green>ownership</font>" of the connection
      from the acceptor to the connection handler.  */</font>
    if (this->peer_acceptor_.accept (*svc_handler) == -1)
      ACE_ERROR_RETURN ((LM_ERROR,
                         "<font color=green>%p</font>",
                         "<font color=green>accept failed</font>"),
                        -1);

    <font color=red>/* Again, most objects need to be open()ed before they are useful.
      We'll give the handler our reactor pointer so that it can
      register for events as well.  If the open fails, we'll force a
      close().  */</font>
    if (svc_handler->open (reactor_) == -1)
      svc_handler->close ();

    return 0;
  }

protected:

  <font color=red>/* Our acceptor object instance */</font>
  ACE_SOCK_Acceptor peer_acceptor_;

  <font color=red>/* A place to remember our reactor pointer */</font>
  ACE_Reactor *reactor_;
};

<font color=blue>#endif</font> <font color=red>/* _CLIENT_ACCEPTOR_H */</font>

</PRE>
<HR WIDTH="100%"></PRE>
It is important to notice here that we have done very little application-specifc
code in developing this object. In fact, if we take out the progress information,
the only app-specific code is when we create the new <I>Logging_Handler</I>
object to give to the <I>accept</I> function. You may begin to wonder why
there isn't a C++ template that does all of this coding for you. Actually,
the ACE toolkit happens to have one handy:
<UL>typedef ACE_Acceptor &lt;<I>YourHandlerClass</I>, ACE_SOCK_ACCEPTOR>
<I>YourAcceptorClass</I>;</UL>
We would have used it like this:
<UL>typedef ACE_Acceptor &lt;Logging_Handler, ACE_SOCK_ACCEPTOR> Client_Acceptor;</UL>
This will create a piece of code similar to what I've shown above. The
primary difference is that the <I>handle_input </I>function created by
the template does NOT register the handler with the reactor. In the long-run,
that is good for us because we can then move that logic into the <I>open</I>
function of the <I>Logging_Handler</I> and use a completely-generic acceptor.

<P>Now that we know how to accept a connection request, let's move on to
the next page where we learn how to handle the actual connection. Even
though we just learned about this cool template thing, we will continue
to use the "hand-written" acceptor developed above. As I mentioned, the
only difference will be in the <I>open</I> function of the connection handler
anyway.

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