diff options
author | jcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1998-09-12 02:48:31 +0000 |
---|---|---|
committer | jcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1998-09-12 02:48:31 +0000 |
commit | 8bb27985db66a8fb5edc79652f8431606ac2cef1 (patch) | |
tree | f85f577817c4372c8aae97aca8830c7d711ef0b7 /docs/tutorials/002/page02.html | |
parent | 022014f634f48668515c3c197172a3aeee2dc454 (diff) | |
download | ATCD-8bb27985db66a8fb5edc79652f8431606ac2cef1.tar.gz |
*** empty log message ***
Diffstat (limited to 'docs/tutorials/002/page02.html')
-rw-r--r-- | docs/tutorials/002/page02.html | 257 |
1 files changed, 96 insertions, 161 deletions
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 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. 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 "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), g_reactor) == -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; - }</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++ 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 "C" 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> "C" 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 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 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) 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> +/* + 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; +} + +static const u_short PORT = ACE_DEFAULT_SERVER_PORT; + +int main (int, char **) +{ + // Create the reactor we'll register our event handler derivatives with. + g_reactor = new ACE_Reactor; + + // Create the acceptor that will listen for client connetions + Logging_Acceptor peer_acceptor; + + /* + 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); + + /* + 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. + */ + ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); + + ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n")); + + // 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; +}</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> |