summaryrefslogtreecommitdiff
path: root/docs/tutorials/005/page05.html
blob: 541fce8d11abf3bef090901b14bcf9fa15602c40 (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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
<!-- $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>Now we're finally at <I><A HREF="client_handler.cpp">client_handler.cpp</A></I>
where we have to write some code.&nbsp; This file has more code than the
rest of the application all together.

<P>
<HR WIDTH="100%">
<PRE>
<font color=red>// $Id$</font>

<font color=red>/* In client_handler.h I alluded to the fact that we'll mess around
   with a Client_Acceptor pointer.  To do so, we need the
   Client_Acceptor object declaration.

   We know that including client_handler.h is redundant because
   client_acceptor.h includes it.  Still, the sentry prevents
   double-inclusion from causing problems and it's sometimes good to
   be explicit about what we're using.

   On the other hand, we don't directly include any ACE header files
   here.  */</font>
<font color=blue>#include</font> "<font color=green>client_acceptor.h</font>"
<font color=blue>#include</font> "<font color=green>client_handler.h</font>"

<font color=red>/* Our constructor doesn't do anything.  That's generally a good idea.
   Unless you want to start throwing exceptions, there isn't a really
   good way to indicate that a constructor has failed.  If I had my
   way, I'd have a boolean return code from it that would cause new to
   return 0 if I failed.  Oh well...  */</font>
<font color=#008888>Client_Handler::Client_Handler</font> (void)
{
}

<font color=red>/* Our destructor doesn't do anything either.  That is also by design.
   Remember, we really want folks to use destroy() to get rid of us.
   If that's so, then there's nothing left to do when the destructor
   gets invoked.  */</font>
<font color=#008888>Client_Handler::~Client_Handler</font> (void)
{
  <font color=red>// Make sure that our peer closes when we're deleted.  This</font>
  <font color=red>// will probably happened when the peer is deleted but it</font>
  <font color=red>// doesn't hurt to be explicit.</font>
  this->peer ().close ();
}

<font color=red>/* The much talked about destroy() method!  The reason I keep going on
   about this is because it's just a Bad Idea (TM) to do real work
   inside of a destructor.  Although this method is void, it really
   should return int so that it can tell the caller there was a
   problem.  Even as void you could at least throw an exception which
   you would never want to do in a destructor.  */</font>
void
<font color=#008888>Client_Handler::destroy</font> (void)
{
  <font color=red>/* Tell the reactor to forget all about us.  Notice that we use the
    same args here that we use in the open() method to register
    ourselves.  In addition, we use the DONT_CALL flag to prevent
    handle_close() being called.  Since we likely got here due to
    handle_close(), that could cause a bit of nasty recursion!  */</font>
  this->reactor ()->remove_handler (this,
                                    ACE_Event_Handler:: READ_MASK | <font color=#008888>ACE_Event_Handler::DONT_CALL</font>);

  <font color=red>/* This is how we're able to tell folks not to use delete.  By
    deleting our own instance, we take care of memory leaks after
    ensuring that the object is shut down correctly.  */</font>
  delete this;
}

<font color=red>/* As mentioned before, the open() method is called by the
   Client_Acceptor when a new client connection has been accepted.
   The Client_Acceptor instance pointer is cast to a void* and given
   to us here.  We'll use that to avoid some global data...  */</font>
int
<font color=#008888>Client_Handler::open</font> (void *_acceptor)
{
  <font color=red>/* Convert the void* to a Client_Acceptor*.  You should probably use
     those fancy ACE_*_cast macros but I can never remember how/when
     to do so.  Since you can cast just about anything around a void*
     without compiler warnings be very sure of what you're doing when
     you do this kind of thing.  That's where the new-style cast
     operators can save you.  */</font>
  Client_Acceptor *acceptor = (Client_Acceptor *) _acceptor;

  <font color=red>/* Our reactor reference will be set when we register ourselves but
     I decided to go ahead and set it here.  No good reason really...  */</font>
  this->reactor (acceptor->reactor ());

  <font color=red>/* We need this to store the address of the client that we are now
     connected to.  We'll use it later to display a debug message.  */</font>
  ACE_INET_Addr addr;

  <font color=red>/* Our ACE_Svc_Handler baseclass gives us the peer() method as a way
     to access our underlying ACE_SOCK_Stream.  On that object, we can
     invoke the get_remote_addr() method to get an ACE_INET_Addr
     having our client's address information. As with most ACE
     methods, we'll get back (and return) a -1 if there was any kind
     of error.  Once we have the ACE_INET_Addr, we can query it to
     find out the clien's host name, TCP/IP address, TCP/IP port value
     and so forth.  One word of warning: the get_host_name() method of
     ACE_INET_Addr may return you an empty string if your name server
     can't resolve it.  On the other hand, get_host_addr() will always
     give you the dotted-decimal string representing the TCP/IP
     address.  */</font>
  if (this->peer ().get_remote_addr (addr) == -1)
    return -1;

  <font color=red>/* If we managed to get the client's address then we're connected to
     a real and valid client.  I suppose that in some cases, the
     client may connect and disconnect so quickly that it is invalid
     by the time we get here. In any case, the test above should
     always be done to ensure that the connection is worth keeping.

     Now, register ourselves with a reactor and tell that reactor that
     we want to be notified when there is something to read.
     Remember, we took our reactor value from the acceptor which
     created us in the first place.  Since we're exploring a
     single-threaded implementation, this is the correct thing to do.  */</font>
  if (this->reactor ()->register_handler (this,
                                          <font color=#008888>ACE_Event_Handler::READ_MASK</font>) == -1)
    ACE_ERROR_RETURN ((LM_ERROR,
                       "<font color=green>(%P|%t) can't register with reactor\n</font>"),
                      -1);

  <font color=red>/* Here, we use the ACE_INET_Addr object to print a message with the
     name of the client we're connected to.  Again, it is possible
     that you'll get an empty string for the host name if your DNS
     isn't configured correctly or if there is some other reason that
     a TCP/IP addreess cannot be converted into a host name.  */</font>
  ACE_DEBUG ((LM_DEBUG,
              "<font color=green>(%P|%t) connected with %s\n</font>",
              addr.get_host_name ()));

  <font color=red>/* Always return zero on success.  */</font>
  return 0;
}

<font color=red>/* In the open() method, we registered with the reactor and requested
   to be notified when there is data to be read.  When the reactor
   sees that activity it will invoke this handle_input() method on us.
   As I mentioned, the _handle parameter isn't useful to us but it
   narrows the list of methods the reactor has to worry about and the
   list of possible virtual functions we would have to override.  */</font>
int
<font color=#008888>Client_Handler::handle_input</font> (ACE_HANDLE handle)
{
  <font color=red>/* Some compilers don't like it when you fail to use a parameter.
     This macro will keep 'em quiet for you.  */</font>
  ACE_UNUSED_ARG (handle);

  <font color=red>/* Now, we create and initialize a buffer for receiving the data.
     Since this is just a simple test app, we'll use a small buffer
     size.  */</font>
  char buf[BUFSIZ];

  <font color=red>/* Invoke the process() method with a pointer to our data area.
     We'll let that method worry about interfacing with the data.  You
     might choose to go ahead and read the data and then pass the
     result to process().  However, application logic may require that
     you read a few bytes to determine what else to read...  It's best
     if we push that all into the application-logic level.  */</font>
  return this->process (buf, sizeof (buf));
}

<font color=red>/* If we return -1 out of handle_input() or if the reactor sees other
   problems with us then handle_close() will be called.  The reactor
   framework will take care of removing us (due to the -1), so we
   don't need to use the destroy() method.  Instead, we just delete
   ourselves directly.  */</font>
int
<font color=#008888>Client_Handler::handle_close</font> (ACE_HANDLE handle,
                              ACE_Reactor_Mask mask)
{
  ACE_UNUSED_ARG (handle);
  ACE_UNUSED_ARG (mask);

  delete this;
  return 0;
}

<font color=red>/* And, at last, we get to the application-logic level.  Out of
   everything we've done so far, this is the only thing that really
   has anything to do with what your application will do.  In this
   method we will read and process the client's data.  In a real
   appliation, you will probably have a bit more in main() to deal
   with command line options but after that point, all of the action
   takes place here.  */</font>
int
<font color=#008888>Client_Handler::process</font> (char *rdbuf,
                         int rdbuf_len)
{
    ssize_t bytes_read = -1;

  <font color=red>/* Using the buffer provided for us, we read the data from the
     client. If there is a read error (eg -- recv() returns -1) then
     it's a pretty good bet that the connection is gone.  Likewise, if
     we read zero bytes then something wrong has happened.  The
     reactor wouldn't have called us if there wasn't some kind of read
     activity but there wouldn't be activity if there were no bytes to
     read...

     On the other hand, if we got some data then we can display it in
     a debug message for everyone to see.  */</font>
    switch ( (bytes_read = this->peer ().recv (rdbuf, rdbuf_len)) )
    {
    case -1: <font color=red>// Complain and leave</font>
      ACE_ERROR_RETURN ((LM_ERROR,
                         "<font color=green>(%P|%t) %p bad read\n</font>",
                         "<font color=green>client</font>"),
                        -1);
    case 0: <font color=red>// Complain and leave</font>
      ACE_ERROR_RETURN ((LM_ERROR,
                         "<font color=green>(%P|%t) closing daemon (fd = %d)\n</font>",
                         this->get_handle ()),
                        -1);
    default: <font color=red>// Show the data</font>
        <font color=red>// NULL-terminate the string before printing it.</font>
      rdbuf[bytes_read] = 0;
      ACE_DEBUG ((LM_DEBUG,
                  "<font color=green>(%P|%t) from client: %s</font>",
                  rdbuf));
    }

   <font color=red>/* It's also worth mentioning that recv() has a cousin: recv_n().
     recv_n() will receive exactly the number of bytes you provide it.
     This is very good when you know exactly how much you expect to
     receive.  For the application here, unfortunately, we don't have
     any idea how much the client will be sending.  recv() will read
     up-to-but-not-more-than the number of bytes we specify (e.g. --
     _rdbuf_len).  That works well when we don't know how much the
     client will provide.  */</font>

  return 0;
}
</PRE>
<P><HR WIDTH="100%">
<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page06.html">Continue This Tutorial</A>]</CENTER>