summaryrefslogtreecommitdiff
path: root/docs/tutorials/006/page05.html
blob: 2b79e79c7b98a9d1941a2bb330727f1cf7f3e98c (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
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
<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="James CE Johnson">
   <META NAME="Description" CONTENT="A first step towards using ACE productively">
   <TITLE>ACE Tutorial 006</TITLE>
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">

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

<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER>


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

<P><A HREF="client_handler.cpp">client_handler.cpp</A>
exposes all the things I've been hinting at.&nbsp; Pay special attention
to the decision made in open() as well as the bit of cleverness in svc().

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

<P><FONT FACE="Arial,Helvetica">// $Id: client_handler.cpp,v 1.1 1998/08/30
23:47:13 schmidt Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">/*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; In client_handler.h I alluded
to the fact that we'll mess around with a</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Client_Acceptor pointer.&nbsp;
To do so, we need the Client_Acceptor object</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; declaration.</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; We know that including client_handler.h
is redundant because</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; client_acceptor.h includes
it.&nbsp; Still, the sentry prevents double-inclusion</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; from causing problems and
it's sometimes good to be explicit about what</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; we're using.</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; On the other hand, we don't
directly include any ACE header files here.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT>
<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">/*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Our constructor doesn't do
anything.&nbsp; That's generally a good idea.&nbsp; Unless</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; you want to start throwing
exceptions, there isn't a really good way to</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; indicate that a constructor
has failed.&nbsp; If I had my way, I'd have a boolean</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; return code from it that
would cause new to return 0 if I failed.&nbsp; Oh</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; well...</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">Client_Handler::Client_Handler (void)</FONT>
<BR><FONT FACE="Arial,Helvetica">{</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; Our destructor doesn't do
anything either.&nbsp; That is also by design.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; Remember, we really want
folks to use destroy() to get rid of us.&nbsp; If that's</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; so, then there's nothing
left to do when the destructor gets invoked.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">Client_Handler::~Client_Handler (void)</FONT>
<BR><FONT FACE="Arial,Helvetica">{</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; The much talked about destroy()
method!&nbsp; The reason I keep going on about</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; this is because it's just
a Bad Idea (TM) to do real work inside of a</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; destructor.&nbsp;&nbsp; Although
this method is void, it really should return</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; int so that it can tell the
caller there was a problem.&nbsp; Even as</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; void you could at least throw
an exception which you would never want</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; to do in a destructor.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">void Client_Handler::destroy (void)</FONT>
<BR><FONT FACE="Arial,Helvetica">{</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; We probably got
here because of an error on the stream, so the peer</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; connection is
probably already closed.&nbsp; Still... there are other ways to</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; get here and
closing a closed peer doesn't hurt.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; this->peer ().close ();</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Tell the reactor
to forget all about us.&nbsp; Notice that we use the same args</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; here that we
use in the open() method to register ourselves.&nbsp; In addition,</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; we use the DONT_CALL
flag to prevent handle_close() being called.&nbsp; Since we</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; likely got here
due to handle_close(), that could cause a bit of nasty</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; recursion!</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; this->reactor ()->remove_handler
(this,</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
ACE_Event_Handler:: READ_MASK | ACE_Event_Handler::DONT_CALL);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; This is how we're
able to tell folks not to use delete.&nbsp; By</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; deleting our
own instance, we take care of memory leaks after ensuring</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; that the object
is shut down correctly.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; delete this;</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; As mentioned before, the
open() method is called by the Client_Acceptor when</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; a new client connection has
been accepted.&nbsp; The Client_Acceptor instance</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; pointer is cast to a void*
and given to us here.&nbsp; We'll use that to avoid</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; some global data...</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">int Client_Handler::open (void *_acceptor)</FONT>
<BR><FONT FACE="Arial,Helvetica">{</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; We need this
to store the address of the client that we are now connected</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; to.&nbsp; We'll
use it later to display a debug message.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_INET_Addr addr;</FONT><FONT FACE="Arial,Helvetica"></FONT>

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

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Convert the void*
to a Client_Acceptor*.&nbsp; You should probably use those</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; fancy new C++
cast operators but I can never remember how/when to do so.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Since you can
cast just about anything around a void* without compiler</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; warnings be very
sure of what you're doing when you do this kind of thing.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; That's where
the new-style cast operators can save you.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; Client_Acceptor *acceptor = (Client_Acceptor
*) _acceptor;</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Our Client_Acceptor
is constructed with a concurrency strategy.&nbsp; Here, we</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; go back to it
to find out what that strategy was.&nbsp; If thread-per-connection</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; was selected
then we simply activate a thread for ourselves and exit.&nbsp; Our</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; svc() method
will then begin executing in that thread.</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; If we are told
to use the single-threaded strategy, there is no difference</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; between this
and the Tutorial 5 implementation.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; if( acceptor->thread_per_connection()
)</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; {</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; return this->activate();</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; }</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Our reactor reference
will be set when we register ourselves but I decided</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; to go ahead and
set it here.&nbsp; No good reason really...</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; this->reactor (acceptor->reactor
());</FONT><FONT FACE="Arial,Helvetica"></FONT>

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

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

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

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Always return
zero on success.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; return 0;</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; As mentioned in the header,
the typical way to close an object in a threaded</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; context is to invoke it's
close() method.&nbsp; Since we already have a handle_close()</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; method built to cleanup after
us, we'll just forward the request on to that</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; object.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">int Client_Handler::close(u_long flags)</FONT>
<BR><FONT FACE="Arial,Helvetica">{</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
this->handle_close(ACE_INVALID_HANDLE,0);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
/*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
After we've taken care of ourselves, call the baseclass method</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
to do any other necessary cleanup.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*/</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return inherited::close();</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; In the open() method, we
registered with the reactor and requested to be</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; notified when there is data
to be read.&nbsp; When the reactor sees that activity</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; it will invoke this handle_input()
method on us.&nbsp; As I mentioned, the _handle</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; parameter isn't useful to
us but it narrows the list of methods the reactor</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; has to worry about and the
list of possible virtual functions we would have</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; to override.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">int Client_Handler::handle_input (ACE_HANDLE
_handle)</FONT>
<BR><FONT FACE="Arial,Helvetica">{</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Some compilers
don't like it when you fail to use a parameter.&nbsp; This macro</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; will keep 'em
quiet for you.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_UNUSED_ARG (_handle);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Now, we create
and initialize a buffer for receiving the data.&nbsp; Since this</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; is just a simple
test app, we'll use a small buffer size.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; char buf[128];</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; memset (buf, 0, sizeof (buf));</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Invoke the process()
method with a pointer to our data area.&nbsp; We'll let</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; that method worry
about interfacing with the data.&nbsp; You might choose to go</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; ahead and read
the data and then pass the result to process().&nbsp; However,</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; application logic
may require that you read a few bytes to determine what</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; else to read...&nbsp;
It's best if we push that all into the application-logic</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; level.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; return this->process (buf, sizeof
(buf));</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; If we return -1 out of handle_input()
or if the reactor sees other problems</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; with us then handle_close()
will be called.&nbsp; It uses our destroy() method to</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; shut us down cleanly and
get rid of our instance.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">int Client_Handler::handle_close (ACE_HANDLE
_handle, ACE_Reactor_Mask _mask)</FONT>
<BR><FONT FACE="Arial,Helvetica">{</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_UNUSED_ARG (_handle);</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; ACE_UNUSED_ARG (_mask);</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; this->destroy ();</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; return 0;</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; The ACE_Svc_Handler&lt;>
is ultimately derived from ACE_Task&lt;>.&nbsp; If you want to</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; create a multi-threaded application,
these are your tools!&nbsp; Simply override</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; the svc() method in your
derivative and arrange for your activate() method</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; to be called.&nbsp; The svc()
method then executes in the new thread.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">int Client_Handler::svc(void)</FONT>
<BR><FONT FACE="Arial,Helvetica">{</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Like handle_input(),
we create a buffer for loading the data.&nbsp; Doing so</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; in handle_input()
doesn't help any but there is a small performance increase</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; by doing this
here:&nbsp; the buffer is created once when the thread is created</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; instead of for
each invocation of process().</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; char buf[128];</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; // Forever...</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; while( 1 )</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; {</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; // Clean the
buffer...</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; memset (buf,
0, sizeof (buf));</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Invoke the proces() method to read and process the data.&nbsp; This is</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
exactly the way it is used by handle_input().&nbsp; That's the reason I</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
created process() in the first place:&nbsp; so that it can be used in either</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
concurrency strategy.&nbsp; Since process() has all of our application-level</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
logic, it's nice that it doesn't have to change when we decide to go</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
multi-threaded.</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Notice that since the recv() method call in process() blocks until</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
there is data ready, this thread doesn't consume any CPU time until</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
there is actually data sent from the client.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; if( this->process(buf,sizeof(buf))
== -1 )</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; {</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return(-1);</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; }</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; }</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp; return(0);</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; And, at last, we get to the
application-logic level.&nbsp; Out of everything</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; we've done so far, this is
the only thing that really has anything to do</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; with what your application
will do.&nbsp; In this method we will read and process</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; the client's data.&nbsp;
In a real appliation, you will probably have a bit more</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; in main() to deal with command
line options but after that point, all of the</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; action takes place here.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;*/</FONT>
<BR><FONT FACE="Arial,Helvetica">int Client_Handler::process (char *_rdbuf,
int _rdbuf_len)</FONT>
<BR><FONT FACE="Arial,Helvetica">{</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; /*</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; Using the buffer
provided for us, we read the data from the client. If</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; there is a read
error (eg -- recv() returns -1) then it's a pretty good</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; bet that the
connection is gone.&nbsp; Likewise, if we read zero bytes then</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; something wrong
has happened.&nbsp; The reactor wouldn't have called us if</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; there wasn't
some kind of read activity but there wouldn't be activity if</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; there were no
bytes to read...</FONT><FONT FACE="Arial,Helvetica"></FONT>

<P><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; On the other hand,
if we got some data then we can display it in a&nbsp; debug</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp; message for everyone
to see.</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp; */</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp; switch (this->peer ().recv (_rdbuf,
_rdbuf_len))</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; {</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; case -1:</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN
((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1);</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; case 0:</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN
((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()),
-1);</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; default:</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_DEBUG
((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf));</FONT>
<BR><FONT FACE="Arial,Helvetica">&nbsp;&nbsp;&nbsp; }</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%">

<P>Well, that's it!&nbsp; After all the talk &amp; the hype, you would
have expected it to be more difficult to create a multi-threaded server.&nbsp;
Surprise!&nbsp; It really is that easy.&nbsp; You still have to handle
contention issues which we haven't addressed here and that is a rather
nasty topic.&nbsp; Still, for the simple case, this is all you have to
do.

<P>The next page is the last for this tutorial.&nbsp; Head on over there
&amp; we'll round up the file list one last time.

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

</BODY>
</HTML>