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
|
<!-- $Id$ -->
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>ACE Tutorial 022</title>
</head>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
<CENTER><B><FONT SIZE=+2>ACE Tutorial 022</FONT></B></CENTER>
<pre>
<font color=red>/* Now that we know the interface, lets proceed to its
implementation. We obviosuly want to include the corresponding header
file. */</font>
<font color=blue>#include</font> "<A
HREF="Acceptor_Service.h">Acceptor_Service.h</A>"
<font color=red>/* A server has to listen for clients at a known
TCP/IP port. The default ACE port is 10002 (at least on my
system) and that's good enough for what we want to do here.
Obviously, a more robust application would take a command line
parameter or read from a configuration file or do some other
clever thing. Just like the signal handler above, though,
that's not what we want to focus on, so we're taking the easy
way out. */</font>
static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
<font color=red>/* As in all our simple tutorials, our contructor also does nothing */</font>
Acceptor_Service::Acceptor_Service (void)
{
<font color=red>// Constructor</font>
}
<font color=red>/* Same in the destructor case */</font>
Acceptor_Service::~Acceptor_Service (void)
{
<font color=red>// Destructor</font>
}
<font color=red>/* This is the virtual method inherited from ACE_Service_Object. This
method is called to initialize the service. In a generic sense, we
initialize everything that is needed to initialize our service
here. Ofcourse we need to do that only if there are not already
initialized. One important point to note here is that we have to
make sure that everything that is initialized here is actually
removed when the service is shutdown */</font>
int
Acceptor_Service::init (int argc, char *argv[])
{
<font color=red>/* As you will see, we will not be using argc and
argv here and hence declare them to be unused variables. This
helps us from the complaints from the picky compilers about
unused variables. */</font>
ACE_UNUSED_ARG (argc);
ACE_UNUSED_ARG (argv);
<font color=red>/* Lets have a debug statement so that we can know that our
Acceptor_Service will be initialized soon */</font>
ACE_DEBUG ((LM_DEBUG,
"Starting the Acceptor_Service\n"));
<font color=red>/* Create an ACE_INET_Addr that represents our endpoint of a
connection. We then open our acceptor object with that Addr.
Doing so tells the acceptor where to listen for connections.
Servers generally listen at "well known" addresses. If not, there
must be some mechanism by which the client is informed of the
server's address. */</font>
if (this->open (ACE_INET_Addr (PORT),
ACE_Reactor::instance ()) == -1)
ACE_ERROR_RETURN ((LM_ERROR,
"%p\n",
"open"),
-1);
return 0;
}
<font color=red>/* This virtual method will be invoked when we pass
a directive to the service configurator framework to remove
our service. Remember the threads and anything else that are
initialized in the init method and remove each of them. If we
leave anything that we initialized still running after this
method is invoked ...well .. you know what happens :-) */ </font>
int
Acceptor_Service::fini (void)
{
<font color=red> /* Lets have another debug statement to inform us the state of the
service. */</font>
ACE_DEBUG ((LM_DEBUG,
"Closing down the Acceptor_Service\n"));
<font color=red> /* Now, lets see what did we start or initialize during the
initialization process. The only thing that we did was opening
our Acceptor to start listening for requests. So, lets close it
down. */</font>
this->close ();
return 0;
}
<font color=red>/* Now, lets see how we can suspend the service that we initialized
and is running. By suspension, we mean that the Reactor still knows
about the service and receives the requests. But, it just keeps
quite even if there are any requests. It actually queues the
requests and sends them to the service once it is resumed.*/</font>
int
Acceptor_Service::suspend (void)
{
<font color=red>/* You must be wondering, as I did, how we can simply suspend this
service without any complex method invocations. Thanks to our
ACE_Reactor class, we can actually suspend the service by just
invoking the following method and passing a pointer to ourself.
This method actually takes care of all the particulars for
suspending the services and keeps us happy. */</font>
ACE_Reactor::instance ()->suspend_handler (this);
return 0;
}
int
Acceptor_Service::resume (void)
{
<font color=red> /* I had the same question again ... how do I do this ?? As before,
our ACE_Reactor class came to a help with this method. ACE
classes do make life simpler .. don't they !! */</font>
ACE_Reactor::instance ()->resume_handler (this);
return 0;
}
<font color=red>/* The macro to be used to define the factory method
and destructor for our dynamically loadable service. */ </font>
ACE_SVC_FACTORY_DEFINE (Acceptor_Service)
<font color=red>/* This macro helps to register a statically linked
service into the service configurator. It is defined in ace/OS.h. All
the parameters needed by the service configurator to build and control the
statically linked servuce are configured in a single structure. An
instance of this structure is statically initialized using this
macro. The First parameter is SERVICE_CLASS i.e. the name of the
class that implements the service. As we did implicitly, this class
must derive from ACE_Service_Configurator. The second parameter is
the NAME of the service. This name is used by the service
configurator to match the configuration options provided in the
svc.conf file. The third parameter is the type of the object which
could be either streams or service objects. The next parameter is
the name of the factory function which we defined in our header
file and above using the macros ACE_FACTORY_DECLARE and
ACE_FACTORY_DEFINE. The fifth parameter are a set of options or
flags which are used to control the ownership and life cycle of the
object. The final argument helps us to choose if we want a new
thread for this service. If the argument is not 0, a thread will be
dedicated to this service. .. lots of parameters .. Huh !! */ </font>
ACE_STATIC_SVC_DEFINE (Acceptor_Service,
ACE_TEXT ("Acceptor_Service"),
ACE_SVC_OBJ_T,
&ACE_SVC_NAME (Acceptor_Service),
ACE_Service_Type::DELETE_THIS | ACE_Service_Type::DELETE_OBJ,
0)
#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION)
template class ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR>;
template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>;
#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA)
#pragma instantiate ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR>
#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */
</PRE>
<P><HR WIDTH="100%">
<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER>
<hr>
<address><a href="mailto:pgontla@ece.uci.edu">Priyanka Gontla</a></address>
<!-- Created: Thu Jan 18 18:24:15 PST 2001 -->
<!-- hhmts start -->
Last modified: Fri Jan 19 11:37:49 PST 2001
<!-- hhmts end -->
</body>
</html>
|