summaryrefslogtreecommitdiff
path: root/docs/tutorials/005/page04.html
blob: 1cede9705cb397fbe36c153c5d368e304930f58f (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
<!-- $Id$ -->
<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>Ok, so we've got a main() loop that sets up the acceptor and we've seen
how easy it is to create the acceptor object.&nbsp; So far, we've hardly
written any code at all.&nbsp; Well, that's just about to change...

<P>First, we look at <I><A HREF="client_handler.h">client_handler.h</A></I>
for the declaration of the Client_Handler object.&nbsp; Then we look at
the definition where all of the real work of the application takes place.

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

<PRE>
<font color=red>// $Id$</font>

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

<font color=red>/* Our client handler must exist somewhere in the ACE_Event_Handler
   object hierarchy.  This is a requirement of the ACE_Reactor because
   it maintains ACE_Event_Handler pointers for each registered event
   handler.  You could derive our Client_Handler directly from
   ACE_Event_Handler but you still have to have an ACE_SOCK_Stream for
   the actual connection.  With a direct derivative of
   ACE_Event_Handler, you'll have to contain and maintain an
   ACE_SOCK_Stream instance yourself.  With ACE_Svc_Handler (which is
   a derivative of ACE_Event_Handler) some of those details are
   handled for you.  */</font>

<font color=blue>#include</font> "<A HREF="../../../ace/Svc_Handler.h">ace/Svc_Handler.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=blue>#include</font> "<A HREF="../../../ace/SOCK_Stream.h">ace/SOCK_Stream.h</A>"

<font color=red>/* Another feature of ACE_Svc_Handler is it's ability to present the
   ACE_Task&lt;> interface as well.  That's what the ACE_NULL_SYNCH
   parameter below is all about.  That's beyond our scope here but
   we'll come back to it in the next tutorial when we start looking at
   concurrency options.  */</font>
class Client_Handler : public ACE_Svc_Handler &lt;ACE_SOCK_STREAM, ACE_NULL_SYNCH>
{
public:
  <font color=red>// Constructor...</font>
  Client_Handler (void);

  <font color=red>/* The destroy() method is our preferred method of destruction.  We
    could have overloaded the delete operator but that is neither easy
    nor intuitive (at least to me).  Instead, we provide a new method
    of destruction and we make our destructor protected so that only
    ourselves, our derivatives and our friends can delete us. It's a
    nice compromise.  */</font>
  void destroy (void);

  <font color=red>/* Most ACE objects have an open() method.  That's how you make them
    ready to do work.  ACE_Event_Handler has a virtual open() method
    which allows us to create an override.  ACE_Acceptor&lt;> will invoke
    this method after creating a new Client_Handler when a client
    connects. Notice that the parameter to open() is a void*.  It just
    so happens that the pointer points to the acceptor which created
    us.  You would like for the parameter to be an ACE_Acceptor&lt;>* but
    since ACE_Event_Handler is generic, that would tie it too closely
    to the ACE_Acceptor&lt;> set of objects.  In our definition of open()
    you'll see how we get around that.  */</font>
  int open (void *acceptor);

  <font color=red>/* When there is activity on a registered handler, the
    handle_input() method of the handler will be invoked.  If that
    method returns an error code (eg -- -1) then the reactor will
    invoke handle_close() to allow the object to clean itself
    up. Since an event handler can be registered for more than one
    type of callback, the callback mask is provided to inform
    handle_close() exactly which method failed.  That way, you don't
    have to maintain state information between your handle_* method
    calls. The &lt;handle> parameter is explained below...  As a
    side-effect, the reactor will also invoke remove_handler() for the
    object on the mask that caused the -1 return.  This means that we
    don't have to do that ourselves!  */</font>
  int handle_close (ACE_HANDLE handle,
                    ACE_Reactor_Mask mask);

protected:

  <font color=red>/* When we register with the reactor, we're going to tell it that we
    want to be notified of READ events.  When the reactor sees that
    there is read activity for us, our handle_input() will be
    invoked. The _handle provided is the handle (file descriptor in
    Unix) of the actual connection causing the activity.  Since we're
    derived from ACE_Svc_Handler&lt;> and it maintains its own peer
    (ACE_SOCK_Stream) object, this is redundant for us.  However, if
    we had been derived directly from ACE_Event_Handler, we may have
    chosen not to contain the peer.  In that case, the &lt;handle> would
    be important to us for reading the client's data.  */</font>
  int handle_input (ACE_HANDLE handle);

  <font color=red>/* This has nothing at all to do with ACE.  I've added this here as
    a worker function which I will call from handle_input().  That
    allows me to introduce concurrency in later tutorials with no
    changes to the worker function.  You can think of process() as
    application-level code and everything else as
    application-framework code.  */</font>
  int process (char *rdbuf, int rdbuf_len);

  <font color=red>/* We don't really do anything in our destructor but we've declared
    it to be protected to prevent casual deletion of this object.  As
    I said above, I really would prefer that everyone goes through the
    destroy() method to get rid of us.  */</font>
  ~Client_Handler (void);
};

<font color=blue>#endif</font> <font color=red>/* CLIENT_HANDLER_H */</font>
</PRE>
<P><HR WIDTH="100%">
<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER>