summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-09-12 02:48:31 +0000
committerjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-09-12 02:48:31 +0000
commit8bb27985db66a8fb5edc79652f8431606ac2cef1 (patch)
treef85f577817c4372c8aae97aca8830c7d711ef0b7 /docs
parent022014f634f48668515c3c197172a3aeee2dc454 (diff)
downloadATCD-8bb27985db66a8fb5edc79652f8431606ac2cef1.tar.gz
*** empty log message ***
Diffstat (limited to 'docs')
-rw-r--r--docs/tutorials/001/Source.tgzbin1745 -> 4801 bytes
-rw-r--r--docs/tutorials/001/acceptor.h153
-rw-r--r--docs/tutorials/001/foo0
-rw-r--r--docs/tutorials/001/logger.h193
-rw-r--r--docs/tutorials/001/page02.html208
-rw-r--r--docs/tutorials/001/page03.html420
-rw-r--r--docs/tutorials/001/page04.html391
-rw-r--r--docs/tutorials/001/page05.html61
-rw-r--r--docs/tutorials/001/server.cpp75
-rw-r--r--docs/tutorials/002/Makefile2
-rw-r--r--docs/tutorials/002/acceptor6
-rw-r--r--docs/tutorials/002/handler81
-rw-r--r--docs/tutorials/002/handler.h137
-rw-r--r--docs/tutorials/002/main36
-rw-r--r--docs/tutorials/002/page02.html257
-rw-r--r--docs/tutorials/002/page03.html199
-rw-r--r--docs/tutorials/002/page04.html276
-rw-r--r--docs/tutorials/002/page05.html41
-rw-r--r--docs/tutorials/002/server.cpp141
19 files changed, 1254 insertions, 1423 deletions
diff --git a/docs/tutorials/001/Source.tgz b/docs/tutorials/001/Source.tgz
index b36b8a6e16d..5f7392a7fc8 100644
--- a/docs/tutorials/001/Source.tgz
+++ b/docs/tutorials/001/Source.tgz
Binary files differ
diff --git a/docs/tutorials/001/acceptor.h b/docs/tutorials/001/acceptor.h
index 8b114e73d6c..988b1948231 100644
--- a/docs/tutorials/001/acceptor.h
+++ b/docs/tutorials/001/acceptor.h
@@ -5,11 +5,28 @@
#if !defined (_CLIENT_ACCEPTOR_H)
#define _CLIENT_ACCEPTOR_H
+/*
+ A SOCK_Acceptor knows how to accept socket connections. We'll use
+ one of those at the heart of our Logging_Acceptor.
+ */
#include "ace/SOCK_Acceptor.h"
+
+/*
+ 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.
+ */
#include "ace/Event_Handler.h"
+/*
+ When a client connects, we'll create a Logging_Handler to deal with the
+ connection. Here, we bring in that declaration.
+ */
#include "logger.h"
+/*
+ Our Logging_Acceptor is derived from ACE_Event_Handler. That lets the
+ reactor treat our acceptor just like every other handler.
+ */
class Logging_Acceptor : public ACE_Event_Handler
{
@@ -17,50 +34,104 @@ friend class Logging_Handler;
public:
- Logging_Acceptor ( const ACE_INET_Addr &addr) : peer_acceptor_(addr)
- {
- }
-
- ~Logging_Acceptor (void)
- {
- this->handle_close (ACE_INVALID_HANDLE, ACE_Event_Handler::READ_MASK);
- }
-
-
- virtual int open (const ACE_INET_Addr &addr)
- {
- if (this->peer_acceptor_.open (addr, 1) == -1)
- return -1;
- else
- return 0;
- }
-
+ /*
+ For this simple case we won't bother with either constructor or
+ destructor. In a real application you would certainly have them.
+ */
+
+ /*
+ 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.
+ */
+ int open (const ACE_INET_Addr &_addr, ACE_Reactor * _reactor )
+ {
+ /*
+ 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.
+ */
+ if (this->peer_acceptor_.open (_addr, 1) == -1)
+ return -1;
+
+ /*
+ Remember the reactor we're using. We'll need it later when we
+ create a client connection handler.
+ */
+ reactor_ = _reactor;
+
+ /*
+ 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.
+ */
+ return _reactor->register_handler( this, ACE_Event_Handler::ACCEPT_MASK );
+ }
+
private:
- virtual ACE_HANDLE get_handle (void) const
- {
- return this->peer_acceptor_.get_handle ();
- }
-
- virtual int handle_input (ACE_HANDLE)
- {
- Logging_Handler *svc_handler = new Logging_Handler;
-
- if (this->peer_acceptor_.accept (*svc_handler) == -1)
- ACE_ERROR_RETURN ((LM_ERROR, "%p", "accept failed"), -1);
- else if (svc_handler->open () == -1)
- svc_handler->close ();
-
- return 0;
- }
-
- virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask)
- {
- return this->peer_acceptor_.close ();
- }
-
-
+ /*
+ To provide multi-OS abstraction, ACE uses the concept of "handles" 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.
+ */
+ ACE_HANDLE get_handle (void) const
+ {
+ return this->peer_acceptor_.get_handle ();
+ }
+
+ /*
+ When an accept request arrives, the reactor will invoke the handle_input()
+ callback. This is where we deal with the connection request.
+ */
+ int handle_input (ACE_HANDLE)
+ {
+ /*
+ 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.
+ */
+ Logging_Handler *svc_handler = new Logging_Handler;
+
+ /*
+ To complete the connection, we invoke the accept() method call on
+ the acceptor object and provide it with the connection handler instance.
+ This transfers "ownership" of the connection from the acceptor to the
+ connection handler.
+ */
+ if (this->peer_acceptor_.accept (*svc_handler) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p", "accept failed"), -1);
+
+ /*
+ 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().
+ */
+ if (svc_handler->open (reactor_) == -1)
+ svc_handler->close ();
+
+ return 0;
+ }
+
+protected:
+
+ /*
+ Our acceptor object instance
+ */
ACE_SOCK_Acceptor peer_acceptor_;
+
+ /*
+ A place to remember our reactor pointer
+ */
+ ACE_Reactor * reactor_;
};
#endif /* _CLIENT_ACCEPTOR_H */
diff --git a/docs/tutorials/001/foo b/docs/tutorials/001/foo
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/docs/tutorials/001/foo
+++ /dev/null
diff --git a/docs/tutorials/001/logger.h b/docs/tutorials/001/logger.h
index 80258702fa9..8063f83f48a 100644
--- a/docs/tutorials/001/logger.h
+++ b/docs/tutorials/001/logger.h
@@ -5,73 +5,156 @@
#if !defined (_CLIENT_HANDLER_H)
#define _CLIENT_HANDLER_H
+/*
+ A connection handler will also be derived from ACE_Event_Handler so that we
+ can register with a reactor.
+ */
#include "ace/Event_Handler.h"
+
#include "ace/INET_Addr.h"
+
+/*
+ Since we're doing TCP/IP, we'll need a SOCK_Stream for the connection.
+ */
#include "ace/SOCK_Stream.h"
class Logging_Handler : public ACE_Event_Handler
{
public:
- Logging_Handler (void)
- {
- }
-
- virtual int open (void)
- {
- if (g_reactor-> register_handler (this, ACE_Event_Handler::READ_MASK) == -1)
- ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
- return 0;
- }
-
- virtual int close (void)
- {
- return this->handle_close (ACE_INVALID_HANDLE, ACE_Event_Handler::RWE_MASK);
- }
+ /*
+ Like the acceptor, we're simple enough to avoid constructor and destructor.
+ */
+
+ /*
+ To open the client handler, we have to register ourselves with the reactor.
+ Notice that we don't have to "open" our ACE_SOCK_Stream member variable.
+ Why? Because the call to the acceptor's accept() method took care of those
+ details for us.
+ */
+ int open ( ACE_Reactor * _reactor )
+ {
+ /*
+ Remember our reactor...
+ */
+ reactor_ = _reactor;
+
+ /*
+ In this case we're using the READ_MASK. Like the acceptor, handle_input()
+ will be called due to this mask but it's a nice piece of bookkeeping to
+ have separate masks for the separate types of activity.
+ */
+ if (_reactor-> register_handler (this, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+ return 0;
+ }
+
+ /*
+ If we're explicitly closed we'll close our "file handle". The net result
+ is to close the connection to the client and remove ourselves from the
+ reactor if we're registered
+ */
+ int close (void)
+ {
+ return this->handle_close (ACE_INVALID_HANDLE, ACE_Event_Handler::RWE_MASK);
+ }
+
+ /*
+ This is a bit of magic... When we call the accept() method of the acceptor
+ object, it wants to do work on an ACE_SOCK_Stream. We have one of those as
+ our connection to the client but it would be gross to provide a method to
+ access that object. It's much cooler if the acceptor can just treat the
+ Logging_Handler as an ACE_SOCK_Stream. Providing this cast operator lets
+ that happen cleanly.
+ */
operator ACE_SOCK_Stream &()
- {
- return this->cli_stream_;
- }
+ {
+ return this->cli_stream_;
+ }
+
+protected:
+
+ /*
+ Again, like the acceptor, we need to provide the connection handle to the reactor.
+ */
+ ACE_HANDLE get_handle (void) const
+ {
+ return this->cli_stream_.get_handle ();
+ }
+
+ /*
+ And here's the handle_input(). This is really the workhorse of the application.
+ */
+ int handle_input (ACE_HANDLE)
+ {
+ /*
+ Create and initialize a small receive buffer.
+ */
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ /*
+ Invoke the recv() method of the ACE_SOCK_Stream to get some data. It will
+ return -1 if there is an error. Otherwise, it will return the number of bytes
+ read. Of course, if it read zero bytes then the connection must be gone.
+ How do I know that? Because handle_input() would not be called by the reactor
+ if there wasn't *some* kind of activity and a closed connection looks like a
+ read request to the reactor. But when you read from a closed connection you'll
+ read zero bytes.
+ Notice that in the error case or closed case we return -1. That tells the reactor
+ to call our handle_close() where we'll take care of shutting down cleanly.
+ */
+ switch( this->cli_stream_.recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n",
+ this->get_handle ()), -1);
+ default:
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
+
+ return 0;
+ }
+
+ /*
+ When handle_input() returns -1, we'll end up here. There are a few housekeeping
+ chores to handle.
+ */
+ int handle_close (ACE_HANDLE, ACE_Reactor_Mask _mask)
+ {
+ /*
+ Remove ourselves from the reactor. We have to include the DONT_CALL in the
+ mask so that it won't call handle_close() on us again!
+ */
+ reactor_->remove_handler(this,_mask|ACE_Event_Handler::DONT_CALL);
+
+ /*
+ Close the socket that we're connected to the client with.
+ */
+ cli_stream_.close();
+
+ /*
+ Since we know we were dynamically allocated by the acceptor, now is a good
+ time to get rid of ourselves.
+ */
+ delete this;
+
+ return 0;
+ }
protected:
- virtual ACE_HANDLE get_handle (void) const
- {
- return this->cli_stream_.get_handle ();
- }
-
- virtual int handle_input (ACE_HANDLE)
- {
- char buf[128];
- memset(buf,0,sizeof(buf));
-
- switch( this->cli_stream_.recv(buf,sizeof buf) )
- {
- case -1:
- ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
- case 0:
- ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n",
- this->get_handle ()), -1);
- default:
- ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
- }
-
- return 0;
- }
-
- virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask)
- {
- delete this;
- return 0;
- }
-
- virtual ~Logging_Handler (void)
- {
- g_reactor-> cancel_timer (this);
- this->cli_stream_.close ();
- }
-
-private:
+
+ /*
+ Our peer connection.
+ */
ACE_SOCK_Stream cli_stream_;
+
+ /*
+ Our reactor (and our acceptor's reactor).
+ */
+ ACE_Reactor * reactor_;
};
#endif /* _CLIENT_HANDLER_H */
diff --git a/docs/tutorials/001/page02.html b/docs/tutorials/001/page02.html
index 5f4ca811e83..f5979936078 100644
--- a/docs/tutorials/001/page02.html
+++ b/docs/tutorials/001/page02.html
@@ -1,121 +1,137 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
- <TITLE>ACE Tutorial 001</TITLE>
- <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <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 001</TITLE>
</HEAD>
-<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 001</FONT></B></CENTER>
+<CENTER><B><FONT SIZE=+2>A Beginners Guide to Using the ACE Toolkit</FONT></B></CENTER>
-<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 001<BR>
-A Beginners Guide to Using the ACE&nbsp;Toolkit</FONT></B></P></CENTER>
<P>
-<HR WIDTH="100%"></P>
+<HR WIDTH="100%">
<P>From here, I want to move on to the main program loop. In a way, we're
starting at the final product when we do this, but it is a very simple
-piece of code and a good place to start.</P>
+piece of code and a good place to start.
-<P>The main program is really quite simple. The real work is done in the
-ACE derived classes.</P>
-
-<UL>
-<PRE>1. #include &quot;acceptor.h&quot;
+<P>The <A HREF="server.cpp">main</A>
+program is really quite simple. The real work is done in the ACE derived
+classes.
-2. ACE_Reactor g_reactor;
-
-3. const unsigned int PORT = 10000;
-
-4. main()
+<P>
+<HR WIDTH="100%">
+<PRE>/*
+&nbsp; Include the header file where our client acceptor is defined.
+&nbsp;*/
+#include "ace/Reactor.h"
+
+/*&nbsp;&nbsp;
+&nbsp; For simplicity, we create our reactor in the global address space.
+&nbsp; In later tutorials we will do something more clever and appropriate. However,
+&nbsp; the purpose of this tutorial is to introduce a connection acceptance and
+&nbsp; handling, not the full capabilities of a reactor.
+*/
+ACE_Reactor * g_reactor;
+
+/*
+&nbsp; Include the header where we define our acceptor object.&nbsp; An acceptor is
+&nbsp; an abstraction that allows a server to "accept" connections from clients.
+*/
+#include "acceptor.h"
+
+/*
+&nbsp; A TCP/IP server can listen to only one port for connection requests.
+&nbsp; Well-known services can always be found at the same address. Lesser-known
+&nbsp; services are generally told where to listen by a configuration file or
+&nbsp; command-line parameter. For this example, we're satisfied with simply hard-coding
+&nbsp; a random but known value.
+*/
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main (int, char **)
{
- 5. ACE_INET_Addr addr(PORT);
-
- 6. Client_Acceptor * ca = new Client_Acceptor(addr);
-
- 7. g_reactor.register_handler(ca,ACE_Event_Handler::READ_MASK);
-
- 8. for(;;) g_reactor.handle_events();
-
- 9. return(0);
-}
-</PRE>
-</UL>
-
-<P>Here's a blow-by-blow account of what's being done:</P>
-
-<OL>
-<LI>Include the header file where our client acceptor is defined.</LI>
-
-<LI>For simplicity, we create our reactor in the global address space.
-In later tutorials we will do something more clever and appropriate. However,
-the purpose of this tutorial is to introduce a connection acceptance and
-handling, not the full capabilities of a reactor.</LI>
-
-<LI>A TCP/IP server can listen to only one <I>port </I>for connection requests.
-Well-known services can always be found at the same address. Lesser-known
-services are generally told where to listen by a configuration file or
-command-line parameter. For this example, we're satisfied with simply hard-coding
-a random but known value.</LI>
-
-<LI>Define the program entry point. Obviously, we are ignoring any command
-line parameters at this point. We may explore other options later.</LI>
-
-<LI>Like the Reactor, I'm skimming over the details of the <I>ADDR</I>
-object. What it provides is an abstraction for addressing services in the
-network. All we need to know at this point is that we are creating an address
-object which specifies the TCP/IP&nbsp;<I>port</I> on which the server
-will listen for new connection requests.</LI>
-
-<LI>Using the address object created above, we now create an acceptor object.
-This is all it takes to create the TCP/IP&nbsp;server and get it ready
-to listen on the specified port. As I understand it, no connections will
-yet be established because the object isn't &quot;open for business&quot;
-at this time. Which brings us to the next line...</LI>
-
-<LI>where the acceptor object is registered with the reactor. Upon registration,
-the reactor <I>open</I>s the object. For an acceptor, this means that client
-requests for connection will now be allowed. In the registration, we also
-tell the reactor that we are interested in <I>read</I> events. A read event
-for an acceptor is a request for connection. When the reactor sees one
-of these events, it will invoke the <I>handle_input</I> member function
-of the acceptor object. The <I>handle_input</I> function will then do whatever
-is necessary to deal with the new connection request. This is discussed
-in detail on the next page of this tutorial.</LI>
-
-<LI>The reactor's <I>handle_events</I> member function is responsible for
-looking at all registered objects and invoking their member function when
-anything of interest occurs. When an event is processed, the <I>handle_events
-</I>function returns. In order to get all events, we embed this in an infinite
-loop.</LI>
-
-<LI>This is redundant since the <I>handle_events</I> infinite loop will
-never exit. Some compilers will complain if it isn't there though, so in
-it goes.</LI>
-</OL>
-
-<P>As I said, the main program is really quite simple:</P>
-
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; Create a Reactor instance.&nbsp; Again, a global pointer isn't exactly the
+&nbsp;&nbsp;&nbsp; best way to handle this but for the simple example here, it will be OK.
+&nbsp;&nbsp;&nbsp; We'll get cute with it later.
+&nbsp; */
+&nbsp; g_reactor = new ACE_Reactor;
+
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; Like the Reactor, I'm skimming over the details of the ADDR
+&nbsp;&nbsp;&nbsp; object. What it provides is an abstraction for addressing services in the
+&nbsp;&nbsp;&nbsp; network. All we need to know at this point is that we are creating an address
+&nbsp;&nbsp;&nbsp; object which specifies the TCP/IP port on which the server
+&nbsp;&nbsp;&nbsp; will listen for new connection requests.
+&nbsp; */
+&nbsp; ACE_INET_Addr addr (PORT);
+
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; We now create an acceptor object.&nbsp; No connections will
+&nbsp;&nbsp;&nbsp; yet be established because the object isn't "open for business"
+&nbsp;&nbsp;&nbsp; at this time. Which brings us to the next line...
+&nbsp; */
+&nbsp; Logging_Acceptor * peer_acceptor = new Logging_Acceptor();
+
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; where the acceptor object is opened.&nbsp; You'll find that most ACE
+&nbsp;&nbsp;&nbsp; objects have to be open()ed before they're of any use to you.
+&nbsp;&nbsp;&nbsp; On this open() call, we're telling the acceptor where to listen
+&nbsp;&nbsp;&nbsp; for connections via the 'addr' object.&nbsp; We're also telling it
+&nbsp;&nbsp;&nbsp; that we want it to be registered with our 'g_reactor' instance.
+&nbsp;&nbsp; */
+&nbsp; if (peer_acceptor->open(addr,g_reactor) == -1 )
+&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN ((LM_ERROR, "Opening Acceptor\n"), -1);
+
+&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; The reactor's handle_events member function is responsible for looking at
+&nbsp;&nbsp;&nbsp; all registered objects and invoking an appropriate member function when
+&nbsp;&nbsp;&nbsp; anything of interest occurs. When an event is processed, the handle_events
+&nbsp;&nbsp;&nbsp; function returns. In order to get all events, we embed this in an infinite
+&nbsp;&nbsp;&nbsp; loop.
+
+&nbsp;&nbsp;&nbsp; Since we put ourselves into an infinite loop, you'll need to CTRL-C
+&nbsp;&nbsp;&nbsp; to exit the program.
+&nbsp; */
+&nbsp; while (1)
+&nbsp;&nbsp;&nbsp;&nbsp; g_reactor-> handle_events ();
+
+&nbsp; return 0;
+}</PRE>
+
+<HR WIDTH="100%">
+
+<P>As I said, the main program is really quite simple:
<UL>
-<LI>Create an address for the <I>port</I> we want to listen to</LI>
+<LI>
+Create an address for the <I>port</I> we want to listen to</LI>
-<LI>Create an acceptor which listens on that address</LI>
+<LI>
+Create an acceptor which listens on that address</LI>
-<LI>Register the acceptor with a reactor to respond to the connection requests</LI>
+<LI>
+Register the acceptor with a reactor to respond to the connection requests</LI>
-<LI>Enter an infinite loop to let the reactor handle the events</LI>
+<LI>
+Enter an infinite loop to let the reactor handle the events</LI>
</UL>
-
-<P>On the next page, we will take a look at the acceptor and how it responds
-to new connection requests.</P>
+On the next page, we will take a look at the acceptor and how it responds
+to new connection requests.
<P>
-<HR WIDTH="100%"></P>
-
-<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page01.html">Previous
-Page</A>] [<A HREF="page03.html">Continue This Tutorial</A>] </P></CENTER>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page01.html">Previous
+Page</A>] [<A HREF="page03.html">Continue
+This Tutorial</A>]</CENTER>
</BODY>
</HTML>
diff --git a/docs/tutorials/001/page03.html b/docs/tutorials/001/page03.html
index 836ba7c1ea8..e6d0b708c16 100644
--- a/docs/tutorials/001/page03.html
+++ b/docs/tutorials/001/page03.html
@@ -1,285 +1,193 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
- <TITLE>ACE Tutorial 001</TITLE>
- <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <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 001</TITLE>
</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>
-
-<P>
-<HR WIDTH="100%"></P>
-
-<P>Now we begin to look at the acceptor object.</P>
-
-<P>I will present the entire object header file first and then disect it
-as with <I>main()</I>.</P>
-
-<UL>
-<PRE>1. #include &lt;stdio.h&gt;
-
-2. #include &quot;ace/Reactor.h&quot;
-3. #include &quot;ace/Event_Handler.h&quot;
-4. #include &quot;ace/SOCK_Acceptor.h&quot;
-5. #include &quot;ace/SOCK_Stream.h&quot;
-6. #include &quot;ace/INET_Addr.h&quot;
-
-7. #include &quot;logger.h&quot;
-
-
-8. extern ACE_Reactor g_reactor;
-
-9. class Client_Acceptor : public ACE_Event_Handler
- {
-
-10. public :
-
-11. Client_Acceptor( const ACE_INET_Addr &amp;addr) : acceptor_(addr) {
-12. if( ! (fp = fopen(&quot;acceptor&quot;,&quot;w+&quot;)) )
-13. fp = stderr;
-
-14. fprintf(fp,&quot;Constructed\n&quot;);
- }
-
-15. virtual int handle_exception(ACE_HANDLE handle)
- {
-16. fprintf(fp,&quot;Exception\n&quot;);
-17. return(-1);
- }
-
-18. virtual int handle_input(ACE_HANDLE handle)
- {
-19. ACE_SOCK_Stream new_connection;
-
-20. this-&gt;acceptor_.accept(new_connection);
-
-21. Logging_Handler *cli_handler = new Logging_Handler(new_connection);
-
-22. fprintf(fp,&quot;Got New Connection\n&quot;);
-
-23. int foo = g_reactor.register_handler(cli_handler,ACE_Event_Handler::RWE_MASK);
-24. return( foo );
- }
-
-25. virtual ACE_HANDLE get_handle(void) const
- {
-26. fprintf(fp,&quot;Providing Handle\n&quot;);
-27. return this-&gt;acceptor_.get_handle();
- }
-
-28. virtual void handle_close(void)
- {
-29. this-&gt;acceptor_.close();
-30. fprintf(fp,&quot;Closing\n&quot;);
- }
-
-31. private :
-32. ACE_SOCK_Acceptor acceptor_;
-33. FILE * fp;
-34. };
-
-</PRE>
-</UL>
-
-<P>Here's a blow-by-blow account of what's being done:</P>
-
-<OL START=1>
-<LI>Include the standard I/O&nbsp;system header file. I only need this
-so that I&nbsp;can use <I>fprintf</I> stuff for the logging function. In
-reality we would probably talk to a database or something.</LI>
-
-<LI>Bring in the ACE headers. Don't worry about the details here.</LI>
-</OL>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
-<OL START=7>
-<LI>Bring in the definition of the <I>logger</I> object. The logger will
-handle connections after our acceptor has accepted the connection. We'll
-look at that on the next page.</LI>
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 001</FONT></B></CENTER>
-<LI>Provide quick access to the reactor object. Later tutorials will be
-more clever than this...</LI>
+<CENTER><B><FONT SIZE=+2>A Beginners Guide to Using the ACE Toolkit</FONT></B></CENTER>
-<LI>Derive our new acceptor object from the ACE_Event_Handler base-class.
-The event handler object is designed to work with the reactor. When an
-event handler is registered with a reactor, the reactor uses member functions
-of the event handler object to gain access to the underlying connection
-<I>handle.</I> We saw this registration process in the previous example
-when the acceptor object was registered with the reactor in the <I>main()</I>
-function. On Unix-type systems, the reactor will then use the <I>select</I>
-system call to wait for activity on the handle (on Win32, <I>WaitForMultipleObjects</I>
-is used instead). Once activity is detected on the handle by the reactor,
-different member functions of the event handler are invoked to process
-the activity. We'll see these in the lines below.</LI>
-<LI>Most of the object is going to be public. When we get a little better
-at what we're doing, we can try to make it safer by declaring some of these
-protected. Most of them can never be private however. Notice at this point
-how each of the functions is declared to be a virtual. This MUST be done
-so that if we later derive a class from here the runtime environment will
-get the member function of the derived class instead of that of the baseclass.</LI>
-
-<LI>The object constructor is the only non-virtual function. We may find
-out later that it should have been virtual! Anyway, we take the single
-parameter, a reference to an address object, and use it to initialize our
-<I>acceptor_</I> object. This is the object which will actually listen
-for client connections. There is a discussion below about why the Acceptor
-is a member of our object rather than it's base class.</LI>
-
-<LI>Remove the gag from the object by giving it somewhere to write debug
-information to. We'll use this file pointer throughout the object to keep
-track of it's internal activities.</LI>
-
-<LI>Fall back to <I>stderr</I> if we failed to open our output file.</LI>
-
-<LI>Status message (duh).</LI>
-
-<LI>The <I>handle_exception</I> member function will be called by the reactor
-if an exception is noticed on the handle associated with this object. In
-the case of a connected socket, an exception is generally caused when the
-remote side closes the connection. In the case of a listening socket, it
-could indicate som rare and strange network failure. See the <I>man</I>
-pages for <I>accept</I> and <I>listen</I> if you really care. For our purposes,
-if we get an exception on our acceptor then we return <I>-1</I> to the
-reactor which tells it we're out of commission. At that point the reactor
-will invoke our <I>close</I> funtion and shut us down.</LI>
-
-<LI>Display notification of the error.</LI>
-
-<LI>Return -1 to tell the reactor that we should be shut down.</LI>
-
-<LI>The <I>handle_input</I> method is called by the reactor whenever our
-handle has some data available for us to process. The actual handle is
-passed into the function but we won't be using it because we know it MUST
-be the <I>acceptor_</I> member object. We could compare the two as a safety
-check though.</LI>
-
-<LI>Now we are creating a new connection. It will be this connection which
-we use to communicate with the client. This will free up the acceptor to
-listen for more connection requests. Because the acceptor as a <I>SOCK
-</I>type object we need to create the connection as a <I>SOCK</I> also.
-An <I>ACE_SOCK_Stream</I> will provide us with an end-to-end connection
-similar to a pipe. This gives us the guarantee that any data we send or
-receive will be complete and in the correct order. An <I>ACE_SOCK_Dgram</I>
-could be used if we don't mind missing some packets or receiving them out
-of order.</LI>
-
-<LI>The <I>acceptor_</I> member object is now told to accept the client
-connection and attach it to the new <I>ACE_SOCK_Stream</I> object we just
-created. This is what frees up the acceptor to listen for more new connections.
-If you don't <I>accept</I> the connection, you cannot read the client's
-data and new clients cannot connect. In fact, after a timeout, the client
-which caused this <I>handle_input</I> callback will give up and assume
-the connection failed.</LI>
-
-<LI>Up to this point, we haven't done anything very specific with regards
-to our application. Here, however, we finally create a <I>logger</I> object
-to handle the connection. The logger object is something we defined in
-<I>logger.h</I>. It is given an <I>ACE_SOCK_Stream</I> object on which
-it will communicate. This is the <B>only</B> application-specific code
-you will find in the <I>Client_Acceptor</I> object we are developing here.</LI>
-
-<LI>Announce the new connection. We could use member functions of <I>new_connection</I>
-to report either of the local and remote systems' addresses and names.</LI>
-
-<LI>Finally, we register our <I>Logging_Handler</I> with our reactor. This
-tells the reactor about our new connection and tells it who to inform when
-there is activity on the connection. Note that we use the <I>RWE</I> mask
-so that we get notification when the connection has data for us to read,
-is available for us to write upon* and when it takes an error. (* Because
-of network buffers and such, you can't necessarily write on a connection
-anytime you want. At times, a <I>write</I> operation on a connection will
-fail or partially fail due to full buffers or some other network issue.
-When that happens, you must cache the remaining data to be written and
-wait for the write-notification event.)</LI>
-
-<LI>Return the result of registering the new connection. If the registration
-failed for some reason, this will cause the <I>handle_input</I> to fail
-and, ultimately, shut down the server. There is probably a much better
-way to handle this but it serves our purposes at the moment.</LI>
-
-<LI><I>get_handle</I> provides an interface layer between the reactor with
-which we're registered and the connection we wish the reactor to operate
-on. The reactor does it's job by monitoring one or more <I>handles</I>.
-In the Unix world, these are simply file descriptors. The <I>get_handle</I>
-method of a communcations object such as our <I>acceptor_</I> returns the
-underlying socket file descriptor associated with the connection. Because
-other OSes work differently, however, the <I>get_handle</I> method provides
-insulation for the programmer. By doing this, the programmer has the option
-of registering many types of objects with a reactor: disk-based file, serial
-port, intra-process pipes, etc...</LI>
-
-<LI>Progress notification.</LI>
-
-<LI>Return the handle of the actual communcation's object.</LI>
-
-<LI>Similar to <I>get_handle</I>, the <I>handle_close</I> is a wrapper
-that allows the reactor to close a connection object. Again, this does
-not have to be an IPC object, it could be anything that supports basic
-open/read/write/close functionality. What we're doing here is shutting
-down the acceptor. You would do this when you want to bring down or pause
-the server.</LI>
-
-<LI>Perform the actual close operation.</LI>
-
-<LI>Another notification</LI>
-
-<LI>Now we begin our brief section of private data. In a real application
-this might be <I>protected</I> instead so that a derived object would have
-direct access to the data members. On the other hand, we may not want that...</LI>
-
-<LI>The <I>acceptor_</I> member object is where all of the action centers.
-It is this object which abstracts all of the socket-level mess necessary
-to listen for client connection requests.</LI>
-
-<LI>The file pointer is our simple way of reporting progress throught the
-program and logging activity from the client.</LI>
+<P>
+<HR WIDTH="100%">
-<LI>All Done.</LI>
-</OL>
+<P>Now we begin to look at the <A HREF="acceptor.h">acceptor</A> object.
-<P>It is important to notice here that we have done very little application-specifc
+<P>
+<HR WIDTH="100%">
+<PRE>
+#if !defined (_CLIENT_ACCEPTOR_H)
+#define _CLIENT_ACCEPTOR_H
+
+/*
+ A SOCK_Acceptor knows how to accept socket connections. We'll use
+ one of those at the heart of our Logging_Acceptor.
+ */
+#include "ace/SOCK_Acceptor.h"
+
+/*
+ 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.
+ */
+#include "ace/Event_Handler.h"
+
+/*
+ When a client connects, we'll create a Logging_Handler to deal with the
+ connection. Here, we bring in that declaration.
+ */
+#include "logger.h"
+
+/*
+ Our Logging_Acceptor is derived from ACE_Event_Handler. That lets the
+ reactor treat our acceptor just like every other handler.
+ */
+class Logging_Acceptor : public ACE_Event_Handler
+{
+
+friend class Logging_Handler;
+
+public:
+
+ /*
+ For this simple case we won't bother with either constructor or
+ destructor. In a real application you would certainly have them.
+ */
+
+ /*
+ 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.
+ */
+ int open (const ACE_INET_Addr &amp;_addr, ACE_Reactor * _reactor )
+ {
+ /*
+ 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.
+ */
+ if (this->peer_acceptor_.open (_addr, 1) == -1)
+ return -1;
+
+ /*
+ Remember the reactor we're using. We'll need it later when we
+ create a client connection handler.
+ */
+ reactor_ = _reactor;
+
+ /*
+ 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.
+ */
+ return _reactor->register_handler( this, ACE_Event_Handler::ACCEPT_MASK );
+ }
+
+private:
+
+ /*
+ To provide multi-OS abstraction, ACE uses the concept of "handles" 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.
+ */
+ ACE_HANDLE get_handle (void) const
+ {
+ return this->peer_acceptor_.get_handle ();
+ }
+
+ /*
+ When an accept request arrives, the reactor will invoke the handle_input()
+ callback. This is where we deal with the connection request.
+ */
+ int handle_input (ACE_HANDLE)
+ {
+ /*
+ 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.
+ */
+ Logging_Handler *svc_handler = new Logging_Handler;
+
+ /*
+ To complete the connection, we invoke the accept() method call on
+ the acceptor object and provide it with the connection handler instance.
+ This transfers "ownership" of the connection from the acceptor to the
+ connection handler.
+ */
+ if (this->peer_acceptor_.accept (*svc_handler) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p", "accept failed"), -1);
+
+ /*
+ 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().
+ */
+ if (svc_handler->open (reactor_) == -1)
+ svc_handler->close ();
+
+ return 0;
+ }
+
+protected:
+
+ /*
+ Our acceptor object instance
+ */
+ ACE_SOCK_Acceptor peer_acceptor_;
+
+ /*
+ A place to remember our reactor pointer
+ */
+ ACE_Reactor * reactor_;
+};
+
+#endif /* _CLIENT_ACCEPTOR_H */
+
+
+<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++&nbsp;template that does all of this coding for you. Actually,
-the ACE toolkit happens to have one handy:</P>
-
-<UL>
-<P>typedef ACE_Acceptor &lt;<I>YourHandlerClass</I>, ACE_SOCK_ACCEPTOR&gt;
-<I>YourAcceptorClass</I>;</P>
-</UL>
-
-<P>We would have used it like this:</P>
-
-<UL>
-<P>typedef ACE_Acceptor &lt;Logging_Handler, ACE_SOCK_ACCEPTOR&gt; Client_Acceptor;</P>
-</UL>
-
-<P>This will create a piece of code similar to what I've shown above. The
+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>
+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 &quot;hand-written&quot; acceptor developed above. As I mentioned,
-the only difference will be in the <I>open</I> function of the connection
-handler anyway.</P>
+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>
-<HR WIDTH="100%"></P>
+<HR WIDTH="100%">
+<CENTER></CENTER>
-<CENTER><P>[<A HREF="..">Tutorial
+<CENTER>[<A HREF="..">Tutorial
Index</A>] [<A HREF="page02.html">Previous
Page</A>] [<A HREF="page04.html">Continue
-This Tutorial</A>] </P></CENTER>
+This Tutorial</A>]</CENTER>
</BODY>
</HTML>
diff --git a/docs/tutorials/001/page04.html b/docs/tutorials/001/page04.html
index 292e7f09c16..5223bb34282 100644
--- a/docs/tutorials/001/page04.html
+++ b/docs/tutorials/001/page04.html
@@ -1,239 +1,204 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
- <TITLE>ACE Tutorial 001</TITLE>
- <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <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 001</TITLE>
</HEAD>
-<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 001</FONT></B></CENTER>
-<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 001<BR>
-A Beginners Guide to Using the ACE&nbsp;Toolkit</FONT></B></P></CENTER>
+<CENTER><B><FONT SIZE=+2>A Beginners Guide to Using the ACE Toolkit</FONT></B></CENTER>
-<P>
-<HR WIDTH="100%"></P>
-<P>Now we begin to look at the acceptor object.</P>
+<P>
+<HR WIDTH="100%">
-<P>I will present the entire object header file first and then disect it
-as with <I>main()</I>.</P>
+<P>Now we begin to look at the <A HREF="logger.h">logger</A>
+object.
-<UL>
-<PRE>
-1. #include &lt;stdio.h&gt;
-
-2. #include &quot;ace/Reactor.h&quot;
-3. #include &quot;ace/SOCK_Acceptor.h&quot;
-4. #include &quot;ace/SOCK_Stream.h&quot;
-5. #include &quot;ace/INET_Addr.h&quot;
-
-
-
-6. class Logging_Handler : public ACE_Event_Handler
- {
-7. public:
-
-8. Logging_Handler(ACE_SOCK_Stream &amp;cs) : client_stream_(cs)
- {
-9. if( ! (fp = fopen(&quot;logger&quot;,&quot;w+&quot;)) )
-10. fp = stderr;
-11. fprintf(fp,&quot;Constructed\n&quot;);
- }
-
-12. virtual int handle_exception(ACE_HANDLE handle)
- {
-13. fprintf(fp,&quot;Exception\n&quot;);
-14. return(-1);
- }
-
-15. virtual int handle_input(ACE_HANDLE handle)
- {
-16. char buf[128];
-
-17. if( this-&gt;client_stream_.recv(buf,sizeof buf) &lt; 1 )
- {
-18. fprintf(fp,&quot;Bad Read\n&quot;);
-19. return(-1);
- }
-20. else
- {
-21. fprintf(fp,&quot;%20.20s\n&quot;,buf);
- }
-22. return(strlen(buf));
- }
-
-23. virtual ACE_HANDLE get_handle(void) const
- {
-24. fprintf(fp,&quot;providing handle\n&quot;);
-25. return this-&gt;client_stream_.get_handle();
- }
-
-26. virtual int handle_close(ACE_HANDLE h, ACE_Reactor_Mask m)
- {
-27. fprintf(fp,&quot;closing\n&quot;);
-28. delete this;
-29. return(0);
- }
-
-30. virtual int close(void)
- {
-31. return this-&gt;handle_close(ACE_INVALID_HANDLE,ACE_Event_Handler::RWE_MASK);
-32. };
-
-33. protected:
-34. ~Logging_Handler(void)
- {
-35. fprintf(fp,&quot;Destruction\n&quot;);
-36. };
+<P>
+<HR WIDTH="100%">
+<PRE>
+#if !defined (_CLIENT_HANDLER_H)
+#define _CLIENT_HANDLER_H
+
+/*
+ A connection handler will also be derived from ACE_Event_Handler so that we
+ can register with a reactor.
+ */
+#include "ace/Event_Handler.h"
+
+#include "ace/INET_Addr.h"
+
+/*
+ Since we're doing TCP/IP, we'll need a SOCK_Stream for the connection.
+ */
+#include "ace/SOCK_Stream.h"
+
+class Logging_Handler : public ACE_Event_Handler
+{
+public:
+
+ /*
+ Like the acceptor, we're simple enough to avoid constructor and destructor.
+ */
+
+ /*
+ To open the client handler, we have to register ourselves with the reactor.
+ Notice that we don't have to "open" our ACE_SOCK_Stream member variable.
+ Why? Because the call to the acceptor's accept() method took care of those
+ details for us.
+ */
+ int open ( ACE_Reactor * _reactor )
+ {
+ /*
+ Remember our reactor...
+ */
+ reactor_ = _reactor;
+
+ /*
+ In this case we're using the READ_MASK. Like the acceptor, handle_input()
+ will be called due to this mask but it's a nice piece of bookkeeping to
+ have separate masks for the separate types of activity.
+ */
+ if (_reactor-> register_handler (this, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+
+ return 0;
+ }
+
+ /*
+ If we're explicitly closed we'll close our "file handle". The net result
+ is to close the connection to the client and remove ourselves from the
+ reactor if we're registered
+ */
+ int close (void)
+ {
+ return this->handle_close (ACE_INVALID_HANDLE, ACE_Event_Handler::RWE_MASK);
+ }
+
+ /*
+ This is a bit of magic... When we call the accept() method of the acceptor
+ object, it wants to do work on an ACE_SOCK_Stream. We have one of those as
+ our connection to the client but it would be gross to provide a method to
+ access that object. It's much cooler if the acceptor can just treat the
+ Logging_Handler as an ACE_SOCK_Stream. Providing this cast operator lets
+ that happen cleanly.
+ */
+ operator ACE_SOCK_Stream &amp;()
+ {
+ return this->cli_stream_;
+ }
+
+protected:
+
+ /*
+ Again, like the acceptor, we need to provide the connection handle to the reactor.
+ */
+ ACE_HANDLE get_handle (void) const
+ {
+ return this->cli_stream_.get_handle ();
+ }
+
+ /*
+ And here's the handle_input(). This is really the workhorse of the application.
+ */
+ int handle_input (ACE_HANDLE)
+ {
+ /*
+ Create and initialize a small receive buffer.
+ */
+ char buf[128];
+ memset(buf,0,sizeof(buf));
+
+ /*
+ Invoke the recv() method of the ACE_SOCK_Stream to get some data. It will
+ return -1 if there is an error. Otherwise, it will return the number of bytes
+ read. Of course, if it read zero bytes then the connection must be gone.
+ How do I know that? Because handle_input() would not be called by the reactor
+ if there wasn't *some* kind of activity and a closed connection looks like a
+ read request to the reactor. But when you read from a closed connection you'll
+ read zero bytes.
+ Notice that in the error case or closed case we return -1. That tells the reactor
+ to call our handle_close() where we'll take care of shutting down cleanly.
+ */
+ switch( this->cli_stream_.recv(buf,sizeof buf) )
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n",
+ this->get_handle ()), -1);
+ default:
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
+ }
-37. private:
-38. ACE_SOCK_Stream client_stream_;
-39. FILE * fp;
-40. };
-
-
-</PRE>
-</UL>
-
-<P>Here's a blow-by-blow account of what's being done:</P>
-
-<OL>
-<LI>Necessary for the <I>fopen</I> and such.</LI>
-
-<LI>We don't actually use a reactor in this object. If we had used the
-template to create our acceptor though, we would have to register ourselves
-with the reactor in our <I>open</I> function.</LI>
-
-<LI>This just shouldn't be here. Again, though, if we wanted to use the
-template to create the acceptor then we would probably do so after the
-object definition instead of dedicating an entire file to it. So, with
-that in mind, we would need the acceptor header or at least one like it.</LI>
-
-<LI>This contains the objects we need to create a connected socket object.
-Where we used an ACE_SOCK_Acceptor object in our acceptor we will use an
-ACE_SOCK_Stream here.</LI>
-
-<LI>This has some handy objects that allow us to get to the address components
-of our connection.</LI>
-
-<LI>Like the acceptor, we derive a new class from the <I>ACE_Event_Handler</I>.
-This gives a signature to the reactor we're registered with so that it
-can cause us to react to activity on the connection.</LI>
-
-<LI>Begin the public section of our object...</LI>
-
-<LI>We are constructed by the acceptor when a new client connection request
-is accepted. At the same time, the acceptor object creates a new <I>SOCK_Stream</I>
-on which we will communicate. That new <I>SOCK_Stream</I> is passed to
-us here so that we can initialize our<I> client_stream_</I> member object.</LI>
+ return 0;
+ }
+
+ /*
+ When handle_input() returns -1, we'll end up here. There are a few housekeeping
+ chores to handle.
+ */
+ int handle_close (ACE_HANDLE, ACE_Reactor_Mask _mask)
+ {
+ /*
+ Remove ourselves from the reactor. We have to include the DONT_CALL in the
+ mask so that it won't call handle_close() on us again!
+ */
+ reactor_->remove_handler(this,_mask|ACE_Event_Handler::DONT_CALL);
+
+ /*
+ Close the socket that we're connected to the client with.
+ */
+ cli_stream_.close();
+
+ /*
+ Since we know we were dynamically allocated by the acceptor, now is a good
+ time to get rid of ourselves.
+ */
+ delete this;
+
+ return 0;
+ }
+
+protected:
+
+ /*
+ Our peer connection.
+ */
+ ACE_SOCK_Stream cli_stream_;
+
+ /*
+ Our reactor (and our acceptor's reactor).
+ */
+ ACE_Reactor * reactor_;
+};
+
+#endif /* _CLIENT_HANDLER_H */</PRE>
-<LI>Open a file we can write our status and log information to. Whatever
-the client sends us we will write here.</LI>
-<LI>Default to <I>stderr</I> if the open fails for some reason.</LI>
-
-<LI>Announce our birth.</LI>
-
-<LI>An exception on a socket generally indicates that the connection closed
-unexpectedly. There are some cases when this may not be fatal (eg -- invoking
-a reactor's <I>notify()</I> method) but for our simple tutorial, we assume
-that any exception is fatal.</LI>
-
-<LI>Log the action</LI>
-
-<LI>Return <I>-1</I> to the reactor to indicate that we should be <I>close</I>ed
-and destroyed.</LI>
-
-<LI><I>handle_input</I> is called by the reactor when there is data to
-be read from the connection. The <I>handle</I> parameter is the handle
-on which the data is present. Since we know the handle is supposed to be
-our <I>client_stream_</I> member object, we don't really need the parameter
-except as a double-check.</LI>
-
-<LI>Create a space for reading the data. We will do a simple-minded receive
-here but a real application could do any number of things.</LI>
-
-<LI>Invoke the <I>recv</I> member function of teh <I>client_stream_</I>
-object. As shown, it will get up to 128 bytes from the connection. Again,
-our simple example won't be stressing this particular limit. Another handy
-<I>SOCK_Stream</I> function is <I>recv_n</I> which will receive an exact
-amount of data even if it isn't all immediately available.</LI>
-
-<LI>We must read at least on byte. If there were none available then the
-reactor wouldn't have invoked the <I>handle_input</I> function in the first
-place. So, if we don't get anything there must be something wrong with
-the connection. Report this to the user.</LI>
-
-<LI>Return <I>-1</I> to get ourselves shut down.</LI>
-
-<LI>However, if the receive operation was successful...</LI>
-
-<LI>Format the received data and write it to the log file.</LI>
-
-<LI>Return a positive number to the reactor. Anything is ok (I think) but
-for giggles, we return the number of bytes received.</LI>
-
-<LI>Wrapper method allowing the reactor to access the connection handle.
-Again, this is necessary because the reactor can only work with file handles
-(aka &quot;file descriptors&quot;).</LI>
-
-<LI>Status message...</LI>
-
-<LI>Provide the handle when requested.</LI>
-
-<LI><I>handle_close</I> will be called by the reactor when it is time to
-shut down the connection. Among the reasons for shutdown is a <I>-1</I>
-return from any of the handlers called by the reactor.</LI>
-
-<LI>Another status message</LI>
-
-<LI>This is a terribly clever and handy thing. There is supposed to be
-some C++&nbsp;magic that will ensure an object can only be instantiated
-dynamically (ie -- via the <I>new</I> operator). Once you guarante that
-then <I>delete this</I> is possible.</LI>
-
-<LI>Return a success status to the reactor now that everything is closed
-correctly.</LI>
-
-<LI>A simple wrapper to <I>handle_close.</I>
-This is only here so that the acceptor can close us down if there is
-an error opening us up...
-</LI>
-
-<LI>Begin the protected part of our object.</LI>
-
-<LI>This helps to ensure that dynamic allocation we were talking about.</LI>
-
-<LI>Yet another status message.</LI>
-
-<LI>Begin the private section of the object.</LI>
-
-<LI>The <I>client_stream</I>_ is what we use to communicate. It can be
-any type of connection object or even, if we're not doing IPC, it could
-be a file descriptor open to a serial port or a data file.</LI>
-
-<LI>A handy file pointer where we can write the status messages and data
-from the client.</LI>
-
-<LI>All done.</LI>
-</OL>
+<P>
+<HR WIDTH="100%">
<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 &quot;hand-written&quot; acceptor developed above. As I mentioned,
-the only difference will be in the <I>open</I> function of the connection
-handler anyway.</P>
+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>
-<HR WIDTH="100%"></P>
+<HR WIDTH="100%">
+<CENTER></CENTER>
-<CENTER><P>[<A HREF="..">Tutorial
+<CENTER>[<A HREF="..">Tutorial
Index</A>] [<A HREF="page03.html">Previous
Page</A>] [<A HREF="page05.html">Continue
-This Tutorial</A>] </P></CENTER>
+This Tutorial</A>]</CENTER>
</BODY>
</HTML>
diff --git a/docs/tutorials/001/page05.html b/docs/tutorials/001/page05.html
index a653ef35e99..5e441d04b11 100644
--- a/docs/tutorials/001/page05.html
+++ b/docs/tutorials/001/page05.html
@@ -1,53 +1,62 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
- <TITLE>ACE Tutorial 001</TITLE>
- <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <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 001</TITLE>
</HEAD>
-<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 001</FONT></B></CENTER>
+<CENTER><B><FONT SIZE=+2>A Beginners Guide to Using the ACE Toolkit</FONT></B></CENTER>
-<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 001<BR>
-A Beginners Guide to Using the ACE&nbsp;Toolkit</FONT></B></P></CENTER>
<P>
-<HR WIDTH="100%"></P>
+<HR WIDTH="100%">
<P>This concludes the first tutorial on using ACE. We've learned how to
create a simple server without knowing very much about network programming.
-</P>
<P>The code used in this tutorial is for illustration purposes. That means
-it may or may not work. I have created a working example which is more
-or less the same as the code in the tutorial. The primary difference is
-that the working code doesn't do all that mucking around with <I>FILE</I>
-pointers and status messages. </P>
-
-<P>You can download all of the <A HREF="Source.tgz">source</A> or individual
-files:</P>
+it may or may not work.&nbsp;&nbsp; Actually, it <I>does</I> work but the
+astute reader will notice a number of places for potential memory leaks.&nbsp;
+We'll work on cleaning those up in future tutorials but if you find one
+feel free to send me a fix &amp;&nbsp;I'll integrate it into the tutorial.
+<P>You can download all of the <A HREF="Source.tgz">source</A>
+or individual files:
<UL>
-<LI><A HREF="00SetEnv">Environment Settings</A></LI>
+<LI>
+<A HREF="00SetEnv">Environment
+Settings</A></LI>
-<LI><A HREF="Makefile">Makefile</A></LI>
+<LI>
+<A HREF="Makefile">Makefile</A></LI>
-<LI><A HREF="server.cpp">main program</A></LI>
+<LI>
+<A HREF="server.cpp">main
+program</A></LI>
-<LI><A HREF="acceptor.h">acceptor object</A></LI>
+<LI>
+<A HREF="acceptor.h">acceptor
+object</A></LI>
-<LI><A HREF="logger.h">connection handler</A></LI>
+<LI>
+<A HREF="logger.h">connection
+handler</A></LI>
</UL>
-
-<P>(The source is a gzip'ed tar file which can be unpacked using <I>winzip</I>
-or the Unix command <I>tar -xvzf filename</I>.)</P>
+(The source is a gzip'ed tar file which can be unpacked using <I>winzip</I>
+or the Unix command <I>tar -xvzf filename</I>.)
<P>
-<HR WIDTH="100%"></P>
+<HR WIDTH="100%">
+<CENTER></CENTER>
-<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Previous
-Page</A>] </P></CENTER>
+<CENTER>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page04.html">Previous
+Page</A>]</CENTER>
</BODY>
</HTML>
diff --git a/docs/tutorials/001/server.cpp b/docs/tutorials/001/server.cpp
index a2a89d22d1a..391b1c18825 100644
--- a/docs/tutorials/001/server.cpp
+++ b/docs/tutorials/001/server.cpp
@@ -2,35 +2,84 @@
// $Id$
+/*
+ Include the header file where our client acceptor is defined.
+ */
#include "ace/Reactor.h"
+
+/*
+ For simplicity, we create our reactor in the global address space.
+ In later tutorials we will do something more clever and appropriate. However,
+ the purpose of this tutorial is to introduce a connection acceptance and
+ handling, not the full capabilities of a reactor.
+*/
ACE_Reactor * g_reactor;
+/*
+ Include the header where we define our acceptor object. An acceptor is
+ an abstraction that allows a server to "accept" connections from clients.
+*/
#include "acceptor.h"
-static sig_atomic_t finished = 0;
-extern "C" void handler (int) { finished = 1; }
-
+/*
+ A TCP/IP server can listen to only one port for connection requests.
+ Well-known services can always be found at the same address. Lesser-known
+ services are generally told where to listen by a configuration file or
+ command-line parameter. For this example, we're satisfied with simply hard-coding
+ a random but known value.
+*/
static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
-int
-main (int argc, char *argv[])
+int main (int, char **)
{
+ /*
+ Create a Reactor instance. Again, a global pointer isn't exactly the
+ best way to handle this but for the simple example here, it will be OK.
+ We'll get cute with it later.
+ */
g_reactor = new ACE_Reactor;
- ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
-
+ /*
+ Like the Reactor, I'm skimming over the details of the ADDR
+ object. What it provides is an abstraction for addressing services in the
+ network. All we need to know at this point is that we are creating an address
+ object which specifies the TCP/IP port on which the server
+ will listen for new connection requests.
+ */
ACE_INET_Addr addr (PORT);
- Logging_Acceptor * peer_acceptor = new Logging_Acceptor(addr);
- if (g_reactor-> register_handler (peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
- ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
+ /*
+ We now create an acceptor object. No connections will
+ yet be established because the object isn't "open for business"
+ at this time. Which brings us to the next line...
+ */
+ Logging_Acceptor * peer_acceptor = new Logging_Acceptor();
+
+ /*
+ where the acceptor object is opened. You'll find that most ACE
+ objects have to be open()ed before they're of any use to you.
+ On this open() call, we're telling the acceptor where to listen
+ for connections via the 'addr' object. We're also telling it
+ that we want it to be registered with our 'g_reactor' instance.
+ */
+ if (peer_acceptor->open(addr,g_reactor) == -1 )
+ ACE_ERROR_RETURN ((LM_ERROR, "Opening Acceptor\n"), -1);
ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
- while (!finished)
- g_reactor-> handle_events ();
+ /*
+ The reactor's handle_events member function is responsible for looking at
+ all registered objects and invoking an appropriate member function when
+ anything of interest occurs. When an event is processed, the handle_events
+ function returns. In order to get all events, we embed this in an infinite
+ loop.
- ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+ Since we put ourselves into an infinite loop, you'll need to CTRL-C
+ to exit the program.
+ */
+ while (1)
+ g_reactor-> handle_events ();
return 0;
}
+
diff --git a/docs/tutorials/002/Makefile b/docs/tutorials/002/Makefile
index 87c2e733b5e..bf06d77195d 100644
--- a/docs/tutorials/002/Makefile
+++ b/docs/tutorials/002/Makefile
@@ -8,7 +8,7 @@
# Local macros
#----------------------------------------------------------------------------
-BIN = server foo
+BIN = server
VLDLIBS = $(LDLIBS:%=%$(VAR))
diff --git a/docs/tutorials/002/acceptor b/docs/tutorials/002/acceptor
deleted file mode 100644
index 45409e4ec3e..00000000000
--- a/docs/tutorials/002/acceptor
+++ /dev/null
@@ -1,6 +0,0 @@
-
-1. #include "ace/Acceptor.h"
-2. #include "ace/SOCK_Acceptor.h"
-
-3. typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
-
diff --git a/docs/tutorials/002/handler b/docs/tutorials/002/handler
deleted file mode 100644
index d987f4c34ff..00000000000
--- a/docs/tutorials/002/handler
+++ /dev/null
@@ -1,81 +0,0 @@
-
-1. #include "ace/SOCK_Acceptor.h"
-2. #include "ace/Reactor.h"
-
-
-3. class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
- {
-
- public:
-
-4. Logging_Handler (void)
- {
- }
-
-5. virtual void destroy (void)
- {
-6. g_reactor->cancel_timer (this);
-7. this->peer ().close ();
- }
-
-8. virtual int open (void *)
- {
-9. ACE_INET_Addr addr;
-
-10. if (this->peer ().get_remote_addr (addr) == -1)
-11. return -1;
-12. else
- {
-13. ACE_OS::strncpy (this->peer_name_, addr.get_host_name (), MAXHOSTNAMELEN + 1);
-
-14. if (g_reactor->register_handler(this, ACE_Event_Handler::READ_MASK) == -1)
-15. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
-
-16. else if (g_reactor->schedule_timer (this, (const void *) this, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
-17. ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
-
-18. else
-19. ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", this->peer_name_));
-
-20. return 0;
- }
- }
-
-21. virtual int close (u_long)
- {
-22. this->destroy ();
-23. return 0;
- }
-
- protected:
-
-24. virtual int handle_input (ACE_HANDLE)
- {
-25. char buf[128];
-26. memset(buf,0,sizeof(buf));
-
-27. switch( this->peer().recv(buf,sizeof buf) )
- {
-28. case -1:
-29. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
-30. case 0:
-31. ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
-32. default:
-33. ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
- }
-
-34. return 0;
- }
-
-35. virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg)
- {
-36. ACE_ASSERT (arg == this);
-37. ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
-38. return 0;
- }
-
- private:
-
-39. char peer_name_[MAXHOSTNAMELEN + 1];
-
- };
diff --git a/docs/tutorials/002/handler.h b/docs/tutorials/002/handler.h
new file mode 100644
index 00000000000..17d8c876728
--- /dev/null
+++ b/docs/tutorials/002/handler.h
@@ -0,0 +1,137 @@
+
+// $Id$
+
+#ifndef LOGGING_HANDLER_H
+#define LOGGING_HANDLER_H
+
+/*
+ Since we used the template to create the acceptor, we don't know if there is a
+ way to get to the reactor it uses. We'll take the easy way out and grab the
+ global pointer. (There is a way to get back to the acceptor's reactor that
+ we'll see later on.)
+ */
+extern ACE_Reactor * g_reactor;
+
+/*
+ This time we're deriving from ACE_Svc_Handler instead of ACE_Event_Handler.
+ The big reason for this is because it already knows how to contain a SOCK_Stream
+ and provides all of the method calls needed by the reactor. The second template
+ parameter is for some advanced stuff we'll do with later servers. For now, just
+ use it as is...
+ */
+class Logging_Handler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH >
+{
+
+public:
+
+ /*
+ The Acceptor<> template will open() us when there is a new client connection.
+ */
+ int open (void *)
+ {
+ ACE_INET_Addr addr;
+
+ /*
+ Ask the peer() (held in our baseclass) to tell us the address of the cient
+ which has connected. There may be valid reasons for this to fail where we
+ wouldn't want to drop the connection but I can't think of one.
+ */
+ if (this->peer ().get_remote_addr (addr) == -1)
+ return -1;
+
+ /*
+ The Acceptor<> won't register us with it's reactor, so we have to do so
+ ourselves. This is where we have to grab that global pointer. Notice
+ that we again use the READ_MASK so that handle_input() will be called
+ when the client does something.
+ */
+ if (g_reactor->register_handler (this, ACE_Event_Handler::READ_MASK) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+
+ /*
+ Here's another new treat. We schedule a timer event. This particular one
+ will fire in two seconds and then every three seconds after that. It doesn't
+ serve any useful purpose in our application other than to show you how it
+ is done.
+ */
+ else if (g_reactor->schedule_timer (this, 0, ACE_Time_Value (2), ACE_Time_Value (3)) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name() ));
+
+ return 0;
+ }
+
+ /*
+ This is a matter of style & maybe taste. Instead of putting all of this stuff
+ into a destructor, we put it here and request that everyone call destroy()
+ instead of 'delete'.
+ */
+ void destroy (void)
+ {
+ /*
+ Cancel that timer we scheduled in open()
+ */
+ g_reactor->cancel_timer (this);
+
+ /*
+ Shut down the connection to the client.
+ */
+ this->peer ().close ();
+
+ /*
+ Free our memory.
+ */
+ delete this;
+ }
+
+ /*
+ If somebody doesn't like us, the will close() us. Actually, if our open() method
+ returns -1, the Acceptor<> will invoke close() on us for cleanup.
+ */
+ int close (u_long)
+ {
+ /*
+ Clean up and go away.
+ */
+ this->destroy ();
+ return 0;
+ }
+
+protected:
+
+ /*
+ Respond to input just like Tutorial 1.
+ */
+ int handle_input (ACE_HANDLE)
+ {
+ char buf[128];
+ memset (buf, 0, sizeof (buf));
+
+ switch (this->peer ().recv (buf, sizeof buf))
+ {
+ case -1:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+ case 0:
+ ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+ default:
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s", buf));
+ }
+
+ return 0;
+ }
+
+ /*
+ When the timer expires, handle_timeout() will be called. The 'arg' is the value passed
+ after 'this' in the schedule_timer() call. You can pass in anything there that you can
+ cast to a void*.
+ */
+ int handle_timeout (const ACE_Time_Value & tv, const void *arg)
+ {
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
+ return 0;
+ }
+
+};
+
+#endif // LOGGING_HANDLER_H
diff --git a/docs/tutorials/002/main b/docs/tutorials/002/main
deleted file mode 100644
index 36c67561463..00000000000
--- a/docs/tutorials/002/main
+++ /dev/null
@@ -1,36 +0,0 @@
-1. #include "ace/Reactor.h"
-
-2. ACE_Reactor * g_reactor;
-
-3. static sig_atomic_t finished = 0;
-4. extern "C" void handler (int) { finished = 1; }
-
-5. static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
-
-6. int main (int argc, char *argv[])
- {
-7. g_reactor = new ACE_Reactor;
-
- // Acceptor factory.
-8. Logging_Acceptor peer_acceptor;
-
-9. if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1)
-10. ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
-
-11. else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
-12. ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
-
-13. ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
-
- // Run forever, performing logging service.
-
-14. ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
-
- // Perform logging service until QUIT_HANDLER receives SIGINT.
-15. while ( !finished )
-16. g_reactor->handle_events ();
-
-17. ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
-
-18. return 0;
- }
diff --git a/docs/tutorials/002/page02.html b/docs/tutorials/002/page02.html
index 8693f9b80fd..46504375fd5 100644
--- a/docs/tutorials/002/page02.html
+++ b/docs/tutorials/002/page02.html
@@ -1,180 +1,115 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
- <TITLE>ACE Tutorial 002</TITLE>
- <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <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 002</TITLE>
</HEAD>
-<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 002</FONT></B></CENTER>
+<CENTER><B><FONT SIZE=+2>Creating a Better Server</FONT></B></CENTER>
-<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 002<BR>
-Creating a Better Server </FONT></B></P></CENTER>
<P>
-<HR WIDTH="100%"></P>
+<HR WIDTH="100%">
-<P>The program is actually small enough to fit into a single source file.
-To make things a little easier to follow, though, I've broken it up into
-three parts: main, acceptor and handler. Each is presented with line numbers
-and description. Because it is a single file, you won't see <I>#include</I>
-directives you may expect. Wait 'till the final page and see the whole
-thing put together before you worry about things like that.</P>
+<P>Like Tutorial 1, this is also a rather small program.&nbsp; I'm going
+to add a couple of new ideas along the way but to make up for it I'm also
+going to simplify the acceptor a great deal.
-<P>
-<HR WIDTH="100%"></P>
-
-<P>We begin by looking at the main portion program:</P>
-
-<UL>
-<PRE>1. #include &quot;ace/Reactor.h&quot;
-
-2. ACE_Reactor * g_reactor;
-
-3. static sig_atomic_t finished = 0;
-4. extern &quot;C&quot; void handler (int) { finished = 1; }
-
-5. static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
-
-6. int main (int argc, char *argv[])
- {
-7. g_reactor = new ACE_Reactor;
-
- // Acceptor factory.
-8. Logging_Acceptor peer_acceptor;
-
-9. if (peer_acceptor.open (ACE_INET_Addr (PORT), g_reactor) == -1)
-10. ACE_ERROR_RETURN ((LM_ERROR, &quot;%p\n&quot;, &quot;open&quot;), -1);
-
-11. else if (g_reactor-&gt;register_handler (&amp;peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
-12. ACE_ERROR_RETURN ((LM_ERROR, &quot;registering service with ACE_Reactor\n&quot;), -1);
-
-13. ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
-
- // Run forever, performing logging service.
-
-14. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) starting up server logging daemon\n&quot;));
-
- // Perform logging service until QUIT_HANDLER receives SIGINT.
-15. while ( !finished )
-16. g_reactor-&gt;handle_events ();
-
-17. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) shutting down server logging daemon\n&quot;));
-
-18. return 0;
- }</PRE>
-</UL>
+<P>We begin by looking at the <A HREF="server.cpp">main</A> portion program:
<P>
-<HR></P>
-
-<OL>
-<LI>The reactor is the only ACE object directly used by the main program.
-We bring in it's definition here.</LI>
-
-<LI>To keep things simple, we again have a global reactor object. This
-time, however, we are keeping a pointer to it. Since C++&nbsp;isn't too
-clear about initialization of global/static objects I chose to dynamically
-create the object in <I>main</I> rather than having it global.</LI>
-
-<LI><I>finished</I> is an atomic data type which we will use to tell us
-the server should exit. It will be set when the program receives an <I>interrupt</I>
-signal.</LI>
-
-<LI>This &quot;C&quot; function will process the <I>interrupt</I> signal
-if it is received by the program. All that it needs to do is set the <I>finished</I>
-flag which our main loop will look at as an indication to exit.</LI>
-
-<LI>The simple variable <I>PORT</I> is statically initialized to a default
-value. This is where the server will listen for new client connection requests.</LI>
-
-<LI>A typical <I>main</I> signature. Although we give ourselves access
-to the command-line arguments, we won't be using them. A more robust example
-might allow specifying the port number or other information via the command-line.</LI>
-
-<LI>The global reactor pointer is now initialized. We could have just as
-easily have chosen to create it on the stack and set <I>g_reactor</I> to
-point to the stack variable. Either way, it gives us more control than
-declaring it outside of <I>main</I>.</LI>
-
-<LI>Now, we create the object which will accept new client requests. Unlike
-the reactor, we did create this one on the stack. In the long run it really
-doesn't matter since Unix is very nice about cleaning up allocated memory
-when the program exits.</LI>
-
-<LI>We now use the acceptor's <I>open</I> member function to get it up
-and running. In the previous example, we passed the <I>port</I> object
-to the acceptor at construction time. This time around, we're passing it
-to <I>open</I> instead. Why? Well, we could have created a constructor
-to accept the <I>port</I> object but we're trying to use one of ACE's tools
-to create a totally generic acceptor. It turns out that that tool creates
-an acceptor that requires the port passed to <I>open</I> rather than the
-constructor. In the long run, this is a good thing because there is no
-good way for a constructor to return a failure. Since we need to know if
-the <I>SOCK_Acceptor</I> is initialized correctly, we are better off initializing
-it in a function that <B>can</B> return an error code. You'll also notice
-that we simply create and pass the <I>port</I> object in one step instead
-of creating an intermediate variable to handle it.
-<br>
-9/11/98 (jcej)
-You can pass a reactor pointer to the open() call to prevent ACE_Singleton::instance()
-being called (more on this in a much later tutorial). This is generally a good idea
-if you've got your own reactor object already.
-</LI>
-
-<LI>We use <I>ACE_ERROR_RETURN</I> to get ourselves out if the <I>open</I>
-call fails. This is a handy and consistent method for reporting nasty things.</LI>
-
-<LI>If the <I>open</I> was successful we will get to here. It is now time
-to register the acceptor with the reactor so that the acceptor's member
-functions will be called when there is activity to be dealt with. Notice
-that we have to pass the address of the acceptor since we created the object
-on the stack instead of with <I>new</I>. Also notice that we're asking
-the reactor to only respond to <I>READ</I> type events. These will be client
-connection requests.</LI>
-
-<LI>Another call to <I>ACE_ERROR_RETURN</I> if the registration failed.</LI>
-
-<LI>An <I>ACE_Sig_Action</I> object is created and given the address of
-the <I>handle</I> &quot;C&quot;&nbsp;function declared above. With that
-function is associated the signal <I>SIGINT</I>. If the program receives
-this signal at any time, the <I>handle</I> function will be called. This
-is our way to cleanly exit the program. There is a much cleaner way to
-do this by creating an object which is registered with the reactor. However,
-I&nbsp;don't want to get into reactor-registered signal handlers at this
-time, so we're going with the easy-out.</LI>
-
-<LI><I>ACE_DEBUG</I> is another function like <I>ACE_ERROR_RETURN</I> that
-we can use to provide consistent messages to the user. Here, we just want
-to report that the program has started.</LI>
-
-<LI>Loop forever unless <I>finished</I> gets a non-zero value. Since the
-only way that can happen is by receipt of an <I>interrupt</I> signal, we
-will keep running until somebody <I>kill</I>s us with that (<I>kill -SIGINT&nbsp;process-id</I>).</LI>
-
-<LI>As always, allow the reactor to handle any events that are generated
-on it's registered event handlers.</LI>
-
-<LI>Announce our departure.</LI>
-
-<LI>Return a successful exit value to the operating system.</LI>
-</OL>
-
-<P>We got a little sloppy by not <I>delete</I>ing the reactor we dynamically
-allocated at the beginning of <I>main</I>. We really should do that for
-sake of completeness and neat programming. Even if we forget though, Unix
-is good about freeing up a program's memory (automatic and dynamically
-allocated)&nbsp;when the program exits.</P>
-
-<P>Now that our re-designed <I>main</I> is dealt with, we will describe
-our much-improved and easier to maintain acceptor object.</P>
+<HR WIDTH="100%">
+<PRE>
+/*
+&nbsp; As before, we need a few ACE objects as well as our Logging_Handler declaration.
+&nbsp;*/
+#include "ace/Acceptor.h"
+#include "ace/SOCK_Acceptor.h"
+#include "ace/Reactor.h"
+#include "handler.h"
+
+/*
+&nbsp; We'll still use the global reactor pointer.&nbsp; There's a snappy way around this
+&nbsp; that shows up in later server tutorials.
+&nbsp;*/
+ACE_Reactor * g_reactor;
+
+/*
+&nbsp; This was hinted at in Tutorial 1.&nbsp; Remember the hand-coded acceptor that we
+&nbsp; created there?&nbsp; This template does all of that and more and better.&nbsp; If you
+&nbsp; find yourself creating code that doesn't feel like a part of your application,
+&nbsp; there's a good chance that ACE has a template or framework component to do
+&nbsp; it for you.
+&nbsp;*/
+typedef ACE_Acceptor &lt; Logging_Handler, ACE_SOCK_ACCEPTOR > Logging_Acceptor;
+
+/*
+&nbsp; One of the new things will be a signal handler so that we can exit the application
+&nbsp; somewhat cleanly.&nbsp; The 'finished' flag is used instead of the previous infninite
+&nbsp; loop and the 'handler' will set that flag in respose to SIGINT (CTRL-C).
+&nbsp;*/
+static sig_atomic_t finished = 0;
+extern "C" void handler (int)
+{
+&nbsp; finished = 1;
+}
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main (int, char **)
+{
+&nbsp; // Create the reactor we'll register our event handler derivatives with.
+&nbsp; g_reactor = new ACE_Reactor;
+
+&nbsp; // Create the acceptor that will listen for client connetions
+&nbsp; Logging_Acceptor peer_acceptor;
+
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; Notice how similar this is to the open() call in Tutorial 1.&nbsp; I read
+&nbsp;&nbsp;&nbsp; ahead when I created that one so that it would come out this way...
+&nbsp;&nbsp; */
+&nbsp; if (peer_acceptor.open (ACE_INET_Addr (PORT), g_reactor) == -1)
+&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
+
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; Here's the easiest way to respond to signals in your application.&nbsp; Simply
+&nbsp;&nbsp;&nbsp; construct an ACE_Sig_Action object with a "C" function and the signal you
+&nbsp;&nbsp;&nbsp; want to capture.&nbsp; As you might expect, there is also a way to register
+&nbsp;&nbsp;&nbsp; signal handlers with a reactor but we take the easy-out here.
+&nbsp;&nbsp; */
+&nbsp; ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
+
+&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
+
+&nbsp; // Perform logging service until the signal handler receives SIGINT.
+&nbsp; while (!finished)
+&nbsp;&nbsp;&nbsp; g_reactor->handle_events ();
+
+&nbsp; // Close the acceptor so that no more clients will be taken in.
+&nbsp; peer_acceptor.close();
+
+&nbsp; // Free up the memory allocated for the reactor.
+&nbsp; delete g_reactor;
+
+&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
+
+&nbsp; return 0;
+}</PRE>
+
<P>
-<HR WIDTH="100%"></P>
+<HR WIDTH="100%">
+<CENTER></CENTER>
-<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>] [<A HREF="page01.html">Previous
-Page</A>] [<A HREF="page03.html">Continue This Tutorial</A>] </P></CENTER>
+<CENTER>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page01.html">Previous
+Page</A>] [<A HREF="page03.html">Continue
+This Tutorial</A>]</CENTER>
</BODY>
</HTML>
diff --git a/docs/tutorials/002/page03.html b/docs/tutorials/002/page03.html
index 38ed438ed18..29bd85fa93e 100644
--- a/docs/tutorials/002/page03.html
+++ b/docs/tutorials/002/page03.html
@@ -1,65 +1,170 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
- <TITLE>ACE Tutorial 002</TITLE>
- <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <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 002</TITLE>
</HEAD>
-<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 002</FONT></B></CENTER>
-<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 002<BR>
-Creating a Better Server </FONT></B></P></CENTER>
+<CENTER><B><FONT SIZE=+2>Creating a Better Server</FONT></B></CENTER>
-<P>
-<HR WIDTH="100%"></P>
-<P>This is what we do to create an acceptor from the ACE&nbsp;template:</P>
+<P>
+<HR WIDTH="100%">
-<UL>
-<PRE>
-1. #include &quot;ace/Acceptor.h&quot;
-2. #include &quot;ace/SOCK_Acceptor.h&quot;
-
-3. typedef ACE_Acceptor &lt;Logging_Handler, ACE_SOCK_ACCEPTOR&gt; Logging_Acceptor;
-</PRE>
-</UL>
+<P>Now lets take a look at the new <A HREF="handler.h">Logging_Handler</A>:
<P>
-<HR></P>
-
-<P>Now, if you think that was difficult, you may as well give up now.</P>
-
-<OL>
-<LI>The <I>Acceptor</I> header file defines the template we're about to
-use. This is a totally generic object where all of the hard work as already
-been done.</LI>
-
-<LI>Because we want to accept connections on an <I>ACE_SOCK_Stream</I>,
-we have to pull in this header. It provides the API details that we will
-need.</LI>
-
-<LI>Finally, create a <I>Logging_Acceptor</I> object based on the <I>ACE_Acceptor</I>
-template. The first parameter <I>Logging_Handler</I> is an object we will
-develop on the next page. This object will be created by the template-generated
-code whenever a new connection request is accepted. The second parameter
-tells the template what kind of acceptor to create. It is most important
-that the first-parameter object and the second parameter be consistent
-in the connetion types used.</LI>
-</OL>
-
-<P>Obviously we're doing things a bit out of order here: <I>main</I> won't
-be happy until it knows what a <I>Logging_Acceptor</I> is and the acceptor
-won't be happy until it knows what a <I>Logging_Handler</I> is. The next
-page pulls in this last definition for us and after that we tie it all
-together.</P>
+<HR WIDTH="100%">
+<BR>&nbsp;
+<PRE>#ifndef LOGGING_HANDLER_H
+#define LOGGING_HANDLER_H
+
+/*
+&nbsp; Since we used the template to create the acceptor, we don't know if there is a
+&nbsp; way to get to the reactor it uses.&nbsp; We'll take the easy way out and grab the
+&nbsp; global pointer.&nbsp; (There is a way to get back to the acceptor's reactor that
+&nbsp; we'll see later on.)
+&nbsp;*/
+extern ACE_Reactor * g_reactor;
+
+/*
+&nbsp; This time we're deriving from ACE_Svc_Handler instead of ACE_Event_Handler.
+&nbsp; The big reason for this is because it already knows how to contain a SOCK_Stream
+&nbsp; and provides all of the method calls needed by the reactor.&nbsp; The second template
+&nbsp; parameter is for some advanced stuff we'll do with later servers.&nbsp; For now, just
+&nbsp; use it as is...
+&nbsp;*/
+class Logging_Handler : public ACE_Svc_Handler &lt; ACE_SOCK_STREAM, ACE_NULL_SYNCH >
+{
+
+public:
+
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; The Acceptor&lt;> template will open() us when there is a new client connection.
+&nbsp;&nbsp; */
+&nbsp; int open (void *)
+&nbsp; {
+&nbsp;&nbsp;&nbsp; ACE_INET_Addr addr;
+
+&nbsp;&nbsp;&nbsp; /*
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ask the peer() (held in our baseclass) to tell us the address of the cient
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; which has connected.&nbsp; There may be valid reasons for this to fail where we
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wouldn't want to drop the connection but I can't think of one.
+&nbsp;&nbsp;&nbsp;&nbsp; */
+&nbsp;&nbsp;&nbsp; if (this->peer ().get_remote_addr (addr) == -1)
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;
+
+&nbsp;&nbsp;&nbsp; /*
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The Acceptor&lt;> won't register us with it's reactor, so we have to do so
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ourselves.&nbsp; This is where we have to grab that global pointer.&nbsp; Notice
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; that we again use the READ_MASK so that handle_input() will be called
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; when the client does something.
+&nbsp;&nbsp;&nbsp;&nbsp; */
+&nbsp;&nbsp;&nbsp; if (g_reactor->register_handler (this, ACE_Event_Handler::READ_MASK) == -1)
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
+
+&nbsp;&nbsp;&nbsp; /*
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Here's another new treat.&nbsp; We schedule a timer event.&nbsp; This particular one
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; will fire in two seconds and then every three seconds after that.&nbsp; It doesn't
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; serve any useful purpose in our application other than to show you how it
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is done.
+&nbsp;&nbsp;&nbsp;&nbsp; */
+&nbsp;&nbsp;&nbsp; else if (g_reactor->schedule_timer (this, 0, ACE_Time_Value (2), ACE_Time_Value (3)) == -1)
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
+
+&nbsp;&nbsp;&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name() ));
+
+&nbsp;&nbsp;&nbsp; return 0;
+&nbsp; }
+
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; This is a matter of style &amp; maybe taste.&nbsp; Instead of putting all of this stuff
+&nbsp;&nbsp;&nbsp; into a destructor, we put it here and request that everyone call destroy()
+&nbsp;&nbsp;&nbsp; instead of 'delete'.
+&nbsp;&nbsp; */
+&nbsp; void destroy (void)
+&nbsp; {
+&nbsp;&nbsp;&nbsp; /*
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Cancel that timer we scheduled in open()
+&nbsp;&nbsp;&nbsp;&nbsp; */
+&nbsp;&nbsp;&nbsp; g_reactor->cancel_timer (this);
+
+&nbsp;&nbsp;&nbsp; /*
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Shut down the connection to the client.
+&nbsp;&nbsp;&nbsp;&nbsp; */
+&nbsp;&nbsp;&nbsp; this->peer ().close ();
+
+&nbsp;&nbsp;&nbsp; /*
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Free our memory.
+&nbsp;&nbsp;&nbsp;&nbsp; */
+&nbsp;&nbsp;&nbsp; delete this;
+&nbsp; }
+
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; If somebody doesn't like us, the will close() us.&nbsp; Actually, if our open() method
+&nbsp;&nbsp;&nbsp; returns -1, the Acceptor&lt;> will invoke close() on us for cleanup.
+&nbsp;&nbsp; */
+&nbsp; int close (u_long)
+&nbsp; {
+&nbsp;&nbsp;&nbsp; /*
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Clean up and go away.
+&nbsp;&nbsp;&nbsp;&nbsp; */
+&nbsp;&nbsp;&nbsp; this->destroy ();
+&nbsp;&nbsp;&nbsp; return 0;
+&nbsp; }
+
+protected:
+
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; Respond to input just like Tutorial 1.
+&nbsp;&nbsp; */
+&nbsp; int handle_input (ACE_HANDLE)
+&nbsp; {
+&nbsp;&nbsp;&nbsp; char buf[128];
+&nbsp;&nbsp;&nbsp; memset (buf, 0, sizeof (buf));
+
+&nbsp;&nbsp;&nbsp; switch (this->peer ().recv (buf, sizeof buf))
+&nbsp;&nbsp;&nbsp; {
+&nbsp;&nbsp;&nbsp; case -1:
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
+&nbsp;&nbsp;&nbsp; case 0:
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
+&nbsp;&nbsp;&nbsp; default:
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s", buf));
+&nbsp;&nbsp;&nbsp; }
+
+&nbsp;&nbsp;&nbsp; return 0;
+&nbsp; }
+
+&nbsp; /*
+&nbsp;&nbsp;&nbsp; When the timer expires, handle_timeout() will be called.&nbsp; The 'arg' is the value passed
+&nbsp;&nbsp;&nbsp; after 'this' in the schedule_timer() call.&nbsp; You can pass in anything there that you can
+&nbsp;&nbsp;&nbsp; cast to a void*.
+&nbsp;&nbsp; */
+&nbsp; int handle_timeout (const ACE_Time_Value &amp; tv, const void *arg)
+&nbsp; {
+&nbsp;&nbsp;&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
+&nbsp;&nbsp;&nbsp; return 0;
+&nbsp; }
+
+};
+
+#endif // LOGGING_HANDLER_H</PRE>
+
<P>
-<HR WIDTH="100%"></P>
+<HR WIDTH="100%">
+<CENTER></CENTER>
-<CENTER><P>[<A HREF="../../Tutorial">Tutorial Index</A>] [<A HREF="page02.html">Previous
-Page</A>] [<A HREF="page04.html">Continue This Tutorial</A>] </P></CENTER>
+<CENTER>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page02.html">Previous
+Page</A>] [<A HREF="page04.html">Continue
+This Tutorial</A>]</CENTER>
</BODY>
</HTML>
diff --git a/docs/tutorials/002/page04.html b/docs/tutorials/002/page04.html
index 5aae2b4205b..14837122aca 100644
--- a/docs/tutorials/002/page04.html
+++ b/docs/tutorials/002/page04.html
@@ -1,271 +1,41 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
- <TITLE>ACE Tutorial 002</TITLE>
- <META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
+ <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 002</TITLE>
</HEAD>
-<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff">
-
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
-<CENTER><P><B><FONT SIZE=+2>ACE&nbsp;Tutorial 002<BR>
-Creating a Better Server </FONT></B></P></CENTER>
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 002</FONT></B></CENTER>
-<P>
-<HR WIDTH="100%"></P>
-
-<P>Since we've gone out of our way to make sure that the other parts of
-the program are generic, you may expect that this final piece, the connection
-handler, will be the most complicated. As usual, you are correct:</P>
+<CENTER><B><FONT SIZE=+2>Creating a Better Server</FONT></B></CENTER>
-<UL>
-<PRE>1. #include &quot;ace/SOCK_Acceptor.h&quot;
-2. #include &quot;ace/Reactor.h&quot;
-
-
-3. class Logging_Handler : public ACE_Svc_Handler&lt;ACE_SOCK_STREAM, ACE_NULL_SYNCH&gt;
- {
-
- public:
-
-4. Logging_Handler (void)
- {
- }
-
-5. virtual void destroy (void)
- {
-6. g_reactor-&gt;cancel_timer (this);
-7. this-&gt;peer ().close ();
- }
-
-8. virtual int open (void *)
- {
-9. ACE_INET_Addr addr;
-
-10. if (this-&gt;peer ().get_remote_addr (addr) == -1)
-11. return -1;
-12. else
- {
-13. ACE_OS::strncpy (this-&gt;peer_name_, addr.get_host_name (), MAXHOSTNAMELEN + 1);
-
-14. if (g_reactor-&gt;register_handler(this, ACE_Event_Handler::READ_MASK) == -1)
-15. ACE_ERROR_RETURN ((LM_ERROR, &quot;(%P|%t) can't register with reactor\n&quot;), -1);
-
-16. else if (g_reactor-&gt;schedule_timer (this, (const void *) this, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
-17. ACE_ERROR_RETURN ((LM_ERROR, &quot;can'(%P|%t) t register with reactor\n&quot;), -1);
-
-18. else
-19. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) connected with %s\n&quot;, this-&gt;peer_name_));
-
-20. return 0;
- }
- }
-
-21. virtual int close (u_long)
- {
-22. this-&gt;destroy ();
-23. return 0;
- }
-
- protected:
-
-24. virtual int handle_input (ACE_HANDLE)
- {
-25. char buf[128];
-26. memset(buf,0,sizeof(buf));
-
-27. switch( this-&gt;peer().recv(buf,sizeof buf) )
- {
-28. case -1:
-29. ACE_ERROR_RETURN ((LM_ERROR, &quot;(%P|%t) %p bad read\n&quot;, &quot;client logger&quot;), -1);
-30. case 0:
-31. ACE_ERROR_RETURN ((LM_ERROR, &quot;(%P|%t) closing log daemon (fd = %d)\n&quot;, this-&gt;get_handle ()), -1);
-32. default:
-33. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) from client: %s&quot;,buf));
- }
-
-34. return 0;
- }
-
-35. virtual int handle_timeout (const ACE_Time_Value &amp;tv, const void *arg)
- {
-36. ACE_ASSERT (arg == this);
-37. ACE_DEBUG ((LM_DEBUG, &quot;(%P|%t) handling timeout from this = %u\n&quot;, this));
-38. return 0;
- }
-
- private:
-
-39. char peer_name_[MAXHOSTNAMELEN + 1];
-
- };
-</PRE>
-</UL>
<P>
-<HR WIDTH="100%"></P>
-
-<P>Here's the step-by-step explanation:</P>
-
-<OL>
-<LI>This has no business being here but I refuse to renumber 38 lines of
-source just to get rid of it.</LI>
-
-<LI>Come to think of it, this is probably not needed either. While we use
-the global reactor object (<I>g_reactor</I>) througout this portion of
-code, we don't actually create any new ones. Besides, we'll drop this code
-into one file with <I>main</I> and <I>acceptor</I> and it won't matter.</LI>
-
-<LI>We've apparently decided to be bold and use yet another ACE template
-to create our <I>Logging_Handler</I> object. From the manual, the <I>ACE_Svc_Handler</I>
-template <I>defines the interface for a service that exchanges data with
-its connected peer</I>. The first template argument specifies the kind
-of connection we want to have. As mentioned on the previous page, this
-<B>must</B> be compatible with the data type used to accept the connection.
-As for the second argument, that's way beyond the scope of what we're
-doing here. Just do it like you see it & we'll get around to explaining
-that in a later tutorial.
-to me.</LI>
-
-<LI>Our default constructor does nothing. We've moved anything with failure
-potential into the <I>open</I> function.
-
-<LI>This should be called instead of <I>delete</I>. It will shut down the
-object gracefully. The other choice is to have a very busy destructor and
-you typically don't want that. Even better, if you make your destructor
-protected then <i>delete</i> cannot be used on your object. Then they have
-to go through <i>destroy()</i> to get rid of it! There are, of course,
-down sides to that as well...
-
-<LI>Cancel any timer(s) which the reactor associates with this object</LI>
-
-<LI>Close the connection to the client. Notice that we use the <I>peer()</I>
-member function generated by the template. We should never need direct
-access to the actual connection object.</LI>
-
-<LI>The <I>open</I> function contains all of our initialization logic.
-It is called by the acceptor when a new connection is accepted. If we fail
-to initialize for any reason, we will return an error code so that the
-acceptor can respond correctly. This could not be done in a constructor.</LI>
-
-<LI>Create a temporary variable that will hold the address of the client
-system.</LI>
-
-<LI>Ask the connection object to give us the address of the client system.
-This is something you will usually want to do for logging or validation
-purposes whenever a new connection is received. See how easy it is?</LI>
-
-<LI>Tell the acceptor if we could not get the peer's address. Shouldn't
-we have used <I>ACE_ERROR_RETURN</I>? You tell me.</LI>
-
-<LI>But, if the peer's address was gotten...</LI>
-
-<LI>Copy the peer's host name into a member variable. We could have simply
-stored the address object but that has more information than we want to
-keep around for a long time. Notice how the <I>ACE_OS</I> class is used
-to access expected &quot;normal&quot; functions. While that may be a bit
-of overkill, it does give us another level of abstraction from one platform
-to another.</LI>
-
-<LI>As usual, we ultimately register ourselves with a reactor. Since we're
-only interested in responding to the client's data, we only ask for <I>READ</I>
-events to be sent to us.</LI>
-
-<LI>Another possible failure point...</LI>
-
-<LI>Just for giggles, we've decided to register a timer event with the
-reactor also. As shown here, it will delay two seconds before firing the
-first timer event and then be rescheduled every two seconds after that.
-Timer resolutions of milliseconds can be used too!</LI>
+<HR WIDTH="100%">
-<LI>But, of course, any registration may fail.</LI>
-
-<LI>Everything must have worked if we got here</LI>
-
-<LI>so tell the driver about it</LI>
-
-<LI>and return success to the acceptor which invoked us.</LI>
-
-<LI>When we're asked to close ourselves, we first destroy the timer and
-peer connection. It seems to me that we should do a <I>delete this</I>
-at some point. Perhaps <I>destroy</I> should do that?</LI>
-
-<LI>Invoke the destroy method to clean everything up</LI>
-
-<LI>and return a success status.</LI>
-
-<LI><I>handle_input</I> is where you do whatever your application requires
-when data is received from the client system.</LI>
-
-<LI>Create a storage space for the received data</LI>
-
-<LI>and make sure it is empty.</LI>
-
-<LI>Receive as much data as we can but don't overrun our buffer. For this
-simple example, we don't get too fancy. In a real application we would
-probably read some number of bytes (4?) and create a number from them.
-We would then use that number to decide how many more bytes to read. The
-number could be a simple byte count or it could be a packet type indicator
-which implies a bytecount.</LI>
-
-<LI>If <I>recv</I> returns <I>-1</I> then there is something bad wrong
-with the connection so</LI>
-
-<LI>we return an <I>-1</I> to the reactor along with a failure message.
-We cannot continue after this.</LI>
-
-<LI>A <I>0</I> return from <I>recv</I> is not quite so bad. However, <I>handle_input</I>
-wouldn't have been called if there was no data to be read. So, we take
-this to be a sign that the client chose to shutdown the connection.</LI>
-<LI>Like the case above, we need to return a <I>-1</I> to the reactor
-so that we can be shutdown. </LI>
-
-<LI>Any other value from <I>recv</I> is taken to indicate the number of
-bytes received so</LI>
-
-<LI>we display the data to the user. In the real world, we could do an
-infinite number of things with the data.</LI>
-
-<LI>Return <I>0</I> if all is well with the receive so that the reactor
-will allow us to continue functioning.</LI>
-
-<LI><I>handle_timeout</I> is something we haven't seen in any example so
-far. Like <I>handle_input</I>, it is called by the reactor based on an
-event. In this case, the event will be expiration of the timer we set in
-the <I>open</I> function.</LI>
-
-<LI>It seems kind of silly for the handler to get a pointer to <I>this</I>
-when the other handlers don't. Still, when given information of this type,
-it is generally good to check it.</LI>
-
-<LI>Display a simple message to tell the user that we got the timer. In
-your program, you may be expecting periodic data from your client. Simply
-set a timer whenver you are through receiving data and cancel it whenever
-you begin receiving it. If the timer handler is ever called, then you know
-you didn't get data within the time you wanted.</LI>
-
-<LI>Returning <I>0</I> will tell the reactor to reschedule the timer as
-configured in the <I>open</I> function.</LI>
-
-<LI>A simple string to hold the name of the client system. We could have
-kept the entire <I>ACE_INET_Addr</I> object but we really only wanted the
-name &amp; not the extra baggage.</LI>
-</OL>
+<P>Well, that's it for the second tutorial. We've found a much easier way
+to create a server, especially the acceptor part. At the same time, we
+introduced more functionality and robustness. Not bad for a day's work.
+<BR>&nbsp;
+<UL>
+<LI>
+<A HREF="00SetEnv">Environment
+Settings</A></LI>
-<P>Obviously this is a bit more complicated than the rest of the program.
-Still, you see there isn't a lot of networking knowlege needed to get this
-up and going. There are unfortunately several questions that I can't answer
-(such as the <I>delete this</I> issue) but given time, I'm sure we'll all
-figure it out.</P>
+<LI>
+<A HREF="Makefile">Makefile</A></LI>
-<P>
-<HR WIDTH="100%"></P>
+<LI>
+<A HREF="server.cpp">server.cpp</A></LI>
+</UL>
-<CENTER><P>[<A HREF="..">Tutorial
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial
Index</A>] [<A HREF="page03.html">Previous
-Page</A>] [<A HREF="page05.html">Continue
-This Tutorial</A>] </P></CENTER>
+Page</A>]</CENTER>
</BODY>
</HTML>
diff --git a/docs/tutorials/002/page05.html b/docs/tutorials/002/page05.html
deleted file mode 100644
index 02a6432f45c..00000000000
--- a/docs/tutorials/002/page05.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<HTML>
-<HEAD>
- <TITLE>ACE Tutorial 002</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 002<BR>
-Creating a Better Server </FONT></B></P></CENTER>
-
-<P>
-<HR WIDTH="100%"></P>
-
-<P>Well, that's it for the second tutorial. We've found a much easier way
-to create a server, especially the acceptor part. At the same time, we
-introduced more functionality and robustness. Not bad for a day's work.</P>
-
-<P>As promised, this all fits together into a single file that is just
-over 120 lines long:</P>
-
-<UL>
-<LI><A HREF="00SetEnv">Environment Settings</A></LI>
-
-<LI><A HREF="Makefile">Makefile</A></LI>
-
-<LI><A HREF="server.cpp">server.cpp</A></LI>
-</UL>
-
-<P>
-<HR WIDTH="100%"></P>
-
-<CENTER><P>[<A HREF="..">Tutorial
-Index</A>] [<A HREF="page03.html">Previous
-Page</A>]</P></CENTER>
-
-</BODY>
-</HTML>
diff --git a/docs/tutorials/002/server.cpp b/docs/tutorials/002/server.cpp
index 2bc1adc2a61..d0c31f0024c 100644
--- a/docs/tutorials/002/server.cpp
+++ b/docs/tutorials/002/server.cpp
@@ -2,130 +2,77 @@
// $Id$
+/*
+ As before, we need a few ACE objects as well as our Logging_Handler declaration.
+ */
#include "ace/Acceptor.h"
#include "ace/SOCK_Acceptor.h"
#include "ace/Reactor.h"
+#include "handler.h"
+/*
+ We'll still use the global reactor pointer. There's a snappy way around this
+ that shows up in later server tutorials.
+ */
ACE_Reactor * g_reactor;
+/*
+ This was hinted at in Tutorial 1. Remember the hand-coded acceptor that we
+ created there? This template does all of that and more and better. If you
+ find yourself creating code that doesn't feel like a part of your application,
+ there's a good chance that ACE has a template or framework component to do
+ it for you.
+ */
+typedef ACE_Acceptor < Logging_Handler, ACE_SOCK_ACCEPTOR > Logging_Acceptor;
+
+/*
+ One of the new things will be a signal handler so that we can exit the application
+ somewhat cleanly. The 'finished' flag is used instead of the previous infninite
+ loop and the 'handler' will set that flag in respose to SIGINT (CTRL-C).
+ */
static sig_atomic_t finished = 0;
-extern "C" void handler (int) { finished = 1; }
-
-// ----------------------------------------
-
-class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
+extern "C" void handler (int)
{
-
-public:
-
- Logging_Handler (void)
- {
- }
-
- virtual void destroy (void)
- {
- g_reactor->cancel_timer (this);
- this->peer ().close ();
- delete this;
- }
-
- virtual int open (void *)
- {
- ACE_INET_Addr addr;
-
- if (this->peer ().get_remote_addr (addr) == -1)
- return -1;
- else
- {
- ACE_OS::strncpy (this->peer_name_, addr.get_host_name (), MAXHOSTNAMELEN + 1);
-
- if (g_reactor->register_handler(this, ACE_Event_Handler::READ_MASK) == -1)
- ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);
-
- else if (g_reactor->schedule_timer (this, (const void *) this, ACE_Time_Value (2), ACE_Time_Value (2)) == -1)
- ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t register with reactor\n"), -1);
-
- else
- ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", this->peer_name_));
-
- return 0;
- }
- }
-
- virtual int close (u_long)
- {
- this->destroy ();
- return 0;
- }
-
-protected:
-
- virtual int handle_input (ACE_HANDLE)
- {
- char buf[128];
- memset(buf,0,sizeof(buf));
-
- switch( this->peer().recv(buf,sizeof buf) )
- {
- case -1:
- ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1);
- case 0:
- ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1);
- default:
- ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s",buf));
- }
-
- return 0;
- }
-
- virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg)
- {
- ACE_ASSERT (arg == this);
- ACE_DEBUG ((LM_DEBUG, "(%P|%t) handling timeout from this = %u\n", this));
- return 0;
- }
-
-private:
-
- char peer_name_[MAXHOSTNAMELEN + 1];
-
-};
-
-
-typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor;
-
+ finished = 1;
+}
static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
-int main (int argc, char *argv[])
+int main (int, char **)
{
+ // Create the reactor we'll register our event handler derivatives with.
g_reactor = new ACE_Reactor;
- // Acceptor factory.
+ // Create the acceptor that will listen for client connetions
Logging_Acceptor peer_acceptor;
- /* Provide a reactor on the open. This prevents ACE_Reactor::instance() from
- creating an unnecessary instance.
+ /*
+ Notice how similar this is to the open() call in Tutorial 1. I read
+ ahead when I created that one so that it would come out this way...
*/
if (peer_acceptor.open (ACE_INET_Addr (PORT), g_reactor) == -1)
ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1);
- /* This is redundant because opening the acceptor with a reactor pointer will
- cause the acceptor to be registered with that reactor.
+ /*
+ Here's the easiest way to respond to signals in your application. Simply
+ construct an ACE_Sig_Action object with a "C" function and the signal you
+ want to capture. As you might expect, there is also a way to register
+ signal handlers with a reactor but we take the easy-out here.
*/
- else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1)
- ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1);
-
ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT);
- // Run forever, performing logging service.
-
ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n"));
- // Perform logging service until QUIT_HANDLER receives SIGINT.
- while ( !finished )
+ // Perform logging service until the signal handler receives SIGINT.
+ while (!finished)
g_reactor->handle_events ();
+ // Close the acceptor so that no more clients will be taken in.
+ peer_acceptor.close();
+
+ // Free up the memory allocated for the reactor.
+ delete g_reactor;
+
ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n"));
return 0;