diff options
Diffstat (limited to 'docs/tutorials')
215 files changed, 0 insertions, 24389 deletions
diff --git a/docs/tutorials/001/00SetEnv b/docs/tutorials/001/00SetEnv deleted file mode 100644 index eca78e10c85..00000000000 --- a/docs/tutorials/001/00SetEnv +++ /dev/null @@ -1,2 +0,0 @@ -export ACE_ROOT=/local/src/ACE/ACE_wrappers -export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH diff --git a/docs/tutorials/001/Makefile b/docs/tutorials/001/Makefile deleted file mode 100644 index 88cbcd3b69c..00000000000 --- a/docs/tutorials/001/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -# -# Makefile for the Reactor Server Logging Daemon -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = server - -FILES = - -LSRC = $(addsuffix .cpp,$(FILES)) -LOBJ = $(addsuffix .o,$(FILES)) -SHOBJ = $(addsuffix .so,$(FILES)) - -LDLIBS = $(addprefix .shobj/,$(SHOBJ)) - -VLDLIBS = $(LDLIBS:%=%$(VAR)) - -BUILD = $(VBIN) - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -.obj/server.o .shobj/server.so: server.cpp acceptor.h logger.h - diff --git a/docs/tutorials/001/Source.tgz b/docs/tutorials/001/Source.tgz Binary files differdeleted file mode 100644 index 5f7392a7fc8..00000000000 --- a/docs/tutorials/001/Source.tgz +++ /dev/null diff --git a/docs/tutorials/001/acceptor.h b/docs/tutorials/001/acceptor.h deleted file mode 100644 index 094e68acdf5..00000000000 --- a/docs/tutorials/001/acceptor.h +++ /dev/null @@ -1,142 +0,0 @@ - -// $Id$ - - -#ifndef _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" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -/* - 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 &_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 */ - diff --git a/docs/tutorials/001/logger.h b/docs/tutorials/001/logger.h deleted file mode 100644 index 6e46176fd6e..00000000000 --- a/docs/tutorials/001/logger.h +++ /dev/null @@ -1,165 +0,0 @@ - -// $Id$ - - -#ifndef _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" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#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 &() - { - 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: - - /* - 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/page01.html b/docs/tutorials/001/page01.html deleted file mode 100644 index f8a921ee48b..00000000000 --- a/docs/tutorials/001/page01.html +++ /dev/null @@ -1,109 +0,0 @@ -<!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 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 Tutorial 001<BR> -A Beginners Guide to Using the ACE Toolkit</FONT></B></P></CENTER> - -<P> -<HR WIDTH="100%"></P> - -<P>The purpose of this tutorial is to show you how to create a very simple -server capable of handling multiple client connections. Unlike a "traditional" -server application, this one handles all requests in one process. Issues -of multi-processing and multi-threading will be handled in later tutorial.</P> - -<P> -<HR WIDTH="100%"></P> - -<P>What do you need to create a server?</P> - -<OL> -<LI>Something which accepts connections from clients</LI> - -<LI>Something which handles established connections</LI> - -<LI>A main program loop that handles it all</LI> -</OL> - -<P>The ACE Acceptor provides a solution for our first requirement. -This class is given a TCP/IP port number on which it will listen for -incoming connections. When a connection is attempted, the acceptor will -create a new object (the handler) to deal with the client connection while -the acceptor goes back to listening for other connections.</P> - -<P>The ACE EventHandler solves our second requirement. This doesn't -seem obvious now but as we progress through this tutorial it will become -more clear.</P> - -<P>Finally, a simple <I>main()</I> function will provide our program loop. -After any program initiallization, it will enter an infinite loop which -waits for connection attempts to the Acceptor or data "events" -on the EventHandler.</P> - -<P> -<HR WIDTH="100%"></P> - -<P>Before we continue, I need to introduce one more ACE concept: the Reactor. -</P> - -<P>I don't want to go into great detail at this time on what the Reactor -is, what it does and how it does it but it is necessary for you to understand -the basic function of a reactor because it is going to be in the first -piece of code you see. The figure below depicts the interrelationships -between the Reactor, the Acceptor and the application handler.</P> -<P> <center> <img src="simple.gif" align=center> </center> - -<P>Briefly:<BR> -The reactor is an object which reacts when things happen to other objects. -These things are called <I>events</I>. The <I>other objects</I> are communications -objects which you have <I>registered</I> with the reactor. At the time -of registration, you also specify which events you are interested in. The -reactor is notified by the operating system when the events of interest -occur within the registered objects. The reactor then uses member functions -of the registered object to process the event. Notice that the reactor -doesn't care what happens because of the event. It is the object's responsibility -to process the event correctly. The reactor simply notifies the object -of the event.</P> - -<P>Why use the reactor?</P> - -<P>That will become clear as the tutorial progresses. For now, however, -a brief answer would be this: it allows multiple simultaneous client connections -to be processed efficiently by a single-threaded server. </P> - -<P>Servers have traditionally created a separate thread or process for -each client served. For large-volume services (such as telnet and ftp) -this is appropriate. However, for small-volume services the overhead of -process creation far outweighs the actual work being done. So... folks -begin using threads instead of processes to handle the clients. This is -good also but still, in some cases, the overhead is too much to bear. Instead, -why not have a single thread handle several clients and use a more intelligent -load-balancing methodology than one-thread-or-process-per-client? -<i>Caveat: Handling all requests in one thread of one process is really -only good when the requests can be handled almost instantaneously.</i> -</P> - -<P>This is where the reactor's power and flexibility come into play. The -developer can begin as a simple, single-threaded application that is later -modified to thread-per-client, process-per-client or thread-pool solution. -<P> -If all of this is gibberish & makes you think that ACE is way to hard to -learn, don't worry. We'll go into all the details & explain as we go. -I only went into all of this so that it can kick around in the back of your -mind until you need it later. -<P> -<HR WIDTH="100%"></P> - -<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>] </P></CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/001/page02.html b/docs/tutorials/001/page02.html deleted file mode 100644 index f5979936078..00000000000 --- a/docs/tutorials/001/page02.html +++ /dev/null @@ -1,137 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 001</TITLE> -</HEAD> -<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> - - -<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>The <A HREF="server.cpp">main</A> -program is really quite simple. The real work is done in the ACE derived -classes. - -<P> -<HR WIDTH="100%"> -<PRE>/* - 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" - -/* - 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, 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; - - /* - 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); - - /* - 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")); - - /* - 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. - - 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; -}</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 acceptor which listens on that address</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> -</UL> -On the next page, we will take a look at the acceptor and how it responds -to new connection requests. - -<P> -<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 deleted file mode 100644 index e6d0b708c16..00000000000 --- a/docs/tutorials/001/page03.html +++ /dev/null @@ -1,193 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 001</TITLE> -</HEAD> -<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> - - -<P> -<HR WIDTH="100%"> - -<P>Now we begin to look at the <A HREF="acceptor.h">acceptor</A> object. - -<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 &_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++ template that does all of this coding for you. Actually, -the ACE toolkit happens to have one handy: -<UL>typedef ACE_Acceptor <<I>YourHandlerClass</I>, ACE_SOCK_ACCEPTOR> -<I>YourAcceptorClass</I>;</UL> -We would have used it like this: -<UL>typedef ACE_Acceptor <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>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 "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%"> -<CENTER></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/001/page04.html b/docs/tutorials/001/page04.html deleted file mode 100644 index 5223bb34282..00000000000 --- a/docs/tutorials/001/page04.html +++ /dev/null @@ -1,204 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 001</TITLE> -</HEAD> -<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> - - -<P> -<HR WIDTH="100%"> - -<P>Now we begin to look at the <A HREF="logger.h">logger</A> -object. - -<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 &() - { - 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: - - /* - Our peer connection. - */ - ACE_SOCK_Stream cli_stream_; - - /* - Our reactor (and our acceptor's reactor). - */ - ACE_Reactor * reactor_; -}; - -#endif /* _CLIENT_HANDLER_H */</PRE> - - -<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 "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%"> -<CENTER></CENTER> - -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page03.html">Previous -Page</A>] [<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/001/page05.html b/docs/tutorials/001/page05.html deleted file mode 100644 index 5e441d04b11..00000000000 --- a/docs/tutorials/001/page05.html +++ /dev/null @@ -1,62 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 001</TITLE> -</HEAD> -<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> - - -<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>The code used in this tutorial is for illustration purposes. That means -it may or may not work. Actually, it <I>does</I> work but the -astute reader will notice a number of places for potential memory leaks. -We'll work on cleaning those up in future tutorials but if you find one -feel free to send me a fix & 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="Makefile">Makefile</A></LI> - -<LI> -<A HREF="server.cpp">main -program</A></LI> - -<LI> -<A HREF="acceptor.h">acceptor -object</A></LI> - -<LI> -<A HREF="logger.h">connection -handler</A></LI> -</UL> -(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%"> -<CENTER></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 deleted file mode 100644 index 391b1c18825..00000000000 --- a/docs/tutorials/001/server.cpp +++ /dev/null @@ -1,85 +0,0 @@ - -// $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" - -/* - 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, 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; - - /* - 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); - - /* - 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")); - - /* - 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. - - 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/001/simple.fig b/docs/tutorials/001/simple.fig deleted file mode 100644 index afea1bddabe..00000000000 --- a/docs/tutorials/001/simple.fig +++ /dev/null @@ -1,57 +0,0 @@ -#FIG 3.2 -Landscape -Center -Inches -Letter -100.00 -Single --2 -1200 2 -6 7800 5925 11850 6900 -2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5 - 11850 6900 11850 5925 7800 5925 7800 6900 11850 6900 -4 0 0 0 0 0 12 0.0000 4 180 3360 7800 6150 Application_Handler (ACE_Event_Handler)\001 -4 0 0 0 0 0 12 0.0000 4 180 3825 7950 6450 handle_input() {read connection, process data ... }\001 -4 0 0 0 0 0 12 0.0000 4 180 1335 7950 6675 get_handle() {...}\001 --6 -2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5 - 5100 7200 5100 5925 1725 5925 1725 7200 5100 7200 -2 1 1 1 1 7 0 0 -1 4.000 0 0 -1 1 0 2 - 2 1 1.00 60.00 120.00 - 4950 6600 7725 6600 -2 1 0 1 4 7 0 0 -1 0.000 0 0 -1 0 1 2 - 2 1 1.00 60.00 120.00 - 3900 5925 5400 2250 -2 1 0 1 4 7 0 0 -1 0.000 0 0 -1 0 1 2 - 2 1 1.00 60.00 120.00 - 8400 5925 6600 2250 -2 1 0 1 12 7 0 0 -1 0.000 0 0 -1 1 0 2 - 2 1 1.00 60.00 120.00 - 4500 5925 6000 2250 -2 1 0 1 12 7 0 0 -1 0.000 0 0 -1 1 0 2 - 2 1 1.00 60.00 120.00 - 9000 5925 7200 2250 -2 1 2 2 24 7 0 0 -1 3.000 0 0 -1 0 1 2 - 0 0 1.00 60.00 120.00 - 3300 7200 3300 8325 -2 1 0 2 15 7 0 0 -1 0.000 0 0 -1 1 1 2 - 0 0 1.00 60.00 120.00 - 0 0 1.00 60.00 120.00 - 9600 6900 9600 8025 -2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5 - 7500 2250 7500 1425 5100 1425 5100 2250 7500 2250 -4 0 0 0 0 0 12 0.0000 4 180 3045 1800 6150 Client_Acceptor (ACE_Event_Handler)\001 -4 0 0 0 0 0 12 0.0000 4 180 2565 1950 6450 handle_input() {open data conn ...\001 -4 0 0 0 0 0 12 0.0000 4 180 1755 3150 6675 create Handler Obj ... }\001 -4 0 0 0 0 0 12 0.0000 4 180 1335 1950 6900 get_handle() {...}\001 -4 0 1 0 0 0 12 0.0000 4 180 1800 5550 6450 create new Handler Obj\001 -4 0 24 0 0 0 12 0.0000 4 180 1530 2550 7800 Connection Request\001 -4 0 15 0 0 0 12 0.0000 4 135 1275 9000 7500 Data Connection\001 -4 0 0 0 0 0 12 0.0000 4 135 600 5925 1725 Reactor\001 -4 0 0 0 0 0 12 0.0000 4 180 1935 5325 2025 event handler dispatching\001 -4 0 0 0 0 0 12 0.0000 4 180 585 8175 4875 register\001 -4 0 0 0 0 0 12 0.0000 4 180 585 4650 5025 register\001 -4 0 0 0 0 0 12 0.0000 4 180 1110 4200 3675 handle_input()\001 -4 0 0 0 0 0 12 0.0000 4 180 975 4200 3900 get_handle()\001 -4 0 0 0 0 0 12 0.0000 4 180 1110 6675 3675 handle_input()\001 -4 0 0 0 0 0 12 0.0000 4 180 975 6675 3900 get_handle()\001 diff --git a/docs/tutorials/001/simple.gif b/docs/tutorials/001/simple.gif Binary files differdeleted file mode 100644 index ef29d88a120..00000000000 --- a/docs/tutorials/001/simple.gif +++ /dev/null diff --git a/docs/tutorials/002/00SetEnv b/docs/tutorials/002/00SetEnv deleted file mode 100644 index eca78e10c85..00000000000 --- a/docs/tutorials/002/00SetEnv +++ /dev/null @@ -1,2 +0,0 @@ -export ACE_ROOT=/local/src/ACE/ACE_wrappers -export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH diff --git a/docs/tutorials/002/Makefile b/docs/tutorials/002/Makefile deleted file mode 100644 index d590e57dac8..00000000000 --- a/docs/tutorials/002/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -# -# Makefile for the Reactor version of the Server Logging Daemon -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = server - -VLDLIBS = $(LDLIBS:%=%$(VAR)) - -BUILD = $(VBIN) - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -# DO NOT DELETE THIS LINE -- g++dep uses it. -# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. - - - -# IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/docs/tutorials/002/handler.h b/docs/tutorials/002/handler.h deleted file mode 100644 index a66ccccb9e6..00000000000 --- a/docs/tutorials/002/handler.h +++ /dev/null @@ -1,159 +0,0 @@ - -// $Id$ - -#ifndef LOGGING_HANDLER_H -#define LOGGING_HANDLER_H - -#include "ace/INET_Addr.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "ace/SOCK_Stream.h" -#include "ace/Reactor.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) - { - /* - Remove ourselves from the reactor - */ - g_reactor->remove_handler(this,ACE_Event_Handler::READ_MASK|ACE_Event_Handler::DONT_CALL); - - /* - 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; - } - - /* - Clean ourselves up when handle_input() (or handle_timer()) returns -1 - */ - int handle_close(ACE_HANDLE, ACE_Reactor_Mask _mask) - { - this->destroy(); - return 0; - } -}; - -#endif // LOGGING_HANDLER_H diff --git a/docs/tutorials/002/page01.html b/docs/tutorials/002/page01.html deleted file mode 100644 index 5bc3fc534a7..00000000000 --- a/docs/tutorials/002/page01.html +++ /dev/null @@ -1,57 +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 Tutorial 002<BR> -Creating a Better Server </FONT></B></P></CENTER> - -<P> -<HR WIDTH="100%"></P> - -<P>In this tutorial, we will build a little on what we learned in the first -tutorial and add a few extras. In the end, we will have a better server -object that is actually simpler and more maintainable than the one we created -before.</P> - -<P> -<HR WIDTH="100%"></P> - -<P>To begin, let's ask ourselves the same thing we did at the beginning -of tutorial 001:</P> - -<UL> -<P>What do you need to create a server?</P> -</UL> - -<OL> -<OL> -<LI>Something which accepts connections from clients</LI> - -<LI>Something which handles established connections</LI> - -<LI>A main program loop that handles it all</LI> -</OL> -</OL> - -<P>Previously, we created a solution which addressed each one of these -questions specifically. At the end of it all, we realized that our only -application-specific coding was confined to the <I>handler</I> portion -of the program. We hinted that there may be a way to eliminate hand-coding -an <I>acceptor</I> each time we want to create a server. Here, we will -explore that approach.</P> - -<P> -<HR WIDTH="100%"></P> - -<CENTER><P>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>] </P></CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/002/page02.html b/docs/tutorials/002/page02.html deleted file mode 100644 index 46504375fd5..00000000000 --- a/docs/tutorials/002/page02.html +++ /dev/null @@ -1,115 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 002</TITLE> -</HEAD> -<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> - - -<P> -<HR WIDTH="100%"> - -<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>We begin by looking at the <A HREF="server.cpp">main</A> portion program: - -<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%"> -<CENTER></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 deleted file mode 100644 index 7fe8c8ab611..00000000000 --- a/docs/tutorials/002/page03.html +++ /dev/null @@ -1,183 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 002</TITLE> -</HEAD> -<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> - - -<P> -<HR WIDTH="100%"> - -<P>Now lets take a look at the new <A HREF="handler.h">Logging_Handler</A>: - -<P> -<HR WIDTH="100%"> -<BR> -<PRE>#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) - { - /* - Remove ourselves from the reactor - */ - g_reactor->remove_handler(this,ACE_Event_Handler::READ_MASK|ACE_Event_Handler::DONT_CALL); - - /* - 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; - } - - /* - Clean ourselves up when handle_input() (or handle_timer()) returns -1 - */ - int handle_close(ACE_HANDLE, ACE_Reactor_Mask _mask) - { - this->destroy(); - return 0; - } -}; - -#endif // LOGGING_HANDLER_H</PRE> - - -<P> -<HR WIDTH="100%"> -<CENTER></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 deleted file mode 100644 index 14837122aca..00000000000 --- a/docs/tutorials/002/page04.html +++ /dev/null @@ -1,41 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 002</TITLE> -</HEAD> -<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> - - -<P> -<HR WIDTH="100%"> - -<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> -<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> - -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page03.html">Previous -Page</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/002/server.cpp b/docs/tutorials/002/server.cpp deleted file mode 100644 index bca90aa01bc..00000000000 --- a/docs/tutorials/002/server.cpp +++ /dev/null @@ -1,89 +0,0 @@ - -// $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; -} - -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; -} - - -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ - diff --git a/docs/tutorials/003/00SetEnv b/docs/tutorials/003/00SetEnv deleted file mode 100644 index eca78e10c85..00000000000 --- a/docs/tutorials/003/00SetEnv +++ /dev/null @@ -1,2 +0,0 @@ -export ACE_ROOT=/local/src/ACE/ACE_wrappers -export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH diff --git a/docs/tutorials/003/Makefile b/docs/tutorials/003/Makefile deleted file mode 100644 index c5da941f1b7..00000000000 --- a/docs/tutorials/003/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -# -# Makefile for client logging applications -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = client - -LSRC = $(addsuffix .cpp,$(BIN)) - -VLDLIBS = $(LDLIBS:%=%$(VAR)) - -BUILD = $(VBIN) - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - diff --git a/docs/tutorials/003/client.cpp b/docs/tutorials/003/client.cpp deleted file mode 100644 index 0886729b4e7..00000000000 --- a/docs/tutorials/003/client.cpp +++ /dev/null @@ -1,105 +0,0 @@ - -// $Id$ - -/* - To establish a socket connection to a server, we'll need an ACE_SOCK_Connector. - */ -#include "ace/SOCK_Connector.h" - -/* - Unlike the previous two Tutorials, we're going to allow the user to provide - command line options this time. Still, we need defaults in case that isn't - done. - */ -static u_short SERVER_PORT = ACE_DEFAULT_SERVER_PORT; -static const char *const SERVER_HOST = ACE_DEFAULT_SERVER_HOST; -static const int MAX_ITERATIONS = 4; - -int main (int argc, char *argv[]) -{ - /* - Accept the users's choice of hosts or use the default. Then do the same - for the TCP/IP port at which the server is listening as well as the - number of iterations to perform. - */ - const char *server_host = argc > 1 ? argv[1] : SERVER_HOST; - u_short server_port = argc > 2 ? ACE_OS::atoi (argv[2]) : SERVER_PORT; - int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : MAX_ITERATIONS; - - /* - Build ourselves a Stream socket. This is a connected socket that provides - reliable end-to-end communications. We will use the server object to send - data to the server we connect to. - */ - ACE_SOCK_Stream server; - - /* - And we need a connector object to establish that connection. The ACE_SOCK_Connector - object provides all of the tools we need to establish a connection once we know the - server's network address... - */ - ACE_SOCK_Connector connector; - - /* - Which we create with an ACE_INET_Addr object. This object is given the TCP/IP port - and hostname of the server we want to connect to. - */ - ACE_INET_Addr addr (server_port, server_host); - - /* - So, we feed the Addr object and the Stream object to the connector's connect() member - function. Given this information, it will establish the network connection to the - server and attacht that connection to the server object. - */ - if (connector.connect (server, addr) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Just for grins, we'll send the server several messages. - */ - for (int i = 0; i < max_iterations; i++) - { - char buf[BUFSIZ]; - - /* - Create our message with the message number - */ - ACE_OS::sprintf (buf, "message = %d\n", i + 1); - - /* - Send the message to the server. We use the server object's send_n() function to - send all of the data at once. There is also a send() function but it may not send - all of the data. That is due to network buffer availability and such. If the send() - doesn't send all of the data, it is up to you to program things such that it will - keep trying until all of the data is sent or simply give up. The send_n() function - already does the "keep tyring" option for us, so we use it. - */ - if (server.send_n ( buf, strlen(buf) ) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - else - { - /* - Pause for a second. - */ - ACE_OS::sleep (1); - } - } - - /* - Close the connection to the server. The servers we've created so far all are based - on the ACE_Reactor. When we close(), the server's reactor will see activity for - the registered event handler and invoke handle_input(). That, in turn, will try - to read from the socket but get back zero bytes. At that point, the server will know - that we've closed from our side. - */ - if (server.close () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1); - } - - return 0; -} diff --git a/docs/tutorials/003/page01.html b/docs/tutorials/003/page01.html deleted file mode 100644 index cbb0a47c8bc..00000000000 --- a/docs/tutorials/003/page01.html +++ /dev/null @@ -1,146 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 003</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 003</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a Simple Client</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Now that we've seen how to create servers, let's spend just a moment -making a client. Since this is so easy, I'm going to do all of it in this -one page. - -<P> -<HR WIDTH="100%"> -<PRE>/* - To establish a socket connection to a server, we'll need an ACE_SOCK_Connector. - */ -#include "ace/SOCK_Connector.h" - -/* - Unlike the previous two Tutorials, we're going to allow the user to provide - command line options this time. Still, we need defaults in case that isn't - done. - */ -static u_short SERVER_PORT = ACE_DEFAULT_SERVER_PORT; -static const char *const SERVER_HOST = ACE_DEFAULT_SERVER_HOST; -static const int MAX_ITERATIONS = 4; - -int main (int argc, char *argv[]) -{ - /* - Accept the users's choice of hosts or use the default. Then do the same - for the TCP/IP port at which the server is listening as well as the - number of iterations to perform. - */ - const char *server_host = argc > 1 ? argv[1] : SERVER_HOST; - u_short server_port = argc > 2 ? ACE_OS::atoi (argv[2]) : SERVER_PORT; - int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : MAX_ITERATIONS; - - /* - Build ourselves a Stream socket. This is a connected socket that provides - reliable end-to-end communications. We will use the server object to send - data to the server we connect to. - */ - ACE_SOCK_Stream server; - - /* - And we need a connector object to establish that connection. The ACE_SOCK_Connector - object provides all of the tools we need to establish a connection once we know the - server's network address... - */ - ACE_SOCK_Connector connector; - - /* - Which we create with an ACE_INET_Addr object. This object is given the TCP/IP port - and hostname of the server we want to connect to. - */ - ACE_INET_Addr addr (server_port, server_host); - - /* - So, we feed the Addr object and the Stream object to the connector's connect() member - function. Given this information, it will establish the network connection to the - server and attacht that connection to the server object. - */ - if (connector.connect (server, addr) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Just for grins, we'll send the server several messages. - */ - for (int i = 0; i < max_iterations; i++) - { - char buf[BUFSIZ]; - - /* - Create our message with the message number - */ - ACE_OS::sprintf (buf, "message = %d\n", i + 1); - - /* - Send the message to the server. We use the server object's send_n() function to - send all of the data at once. There is also a send() function but it may not send - all of the data. That is due to network buffer availability and such. If the send() - doesn't send all of the data, it is up to you to program things such that it will - keep trying until all of the data is sent or simply give up. The send_n() function - already does the "keep tyring" option for us, so we use it. - */ - if (server.send_n ( buf, strlen(buf) ) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - else - { - /* - Pause for a second. - */ - ACE_OS::sleep (1); - } - } - - /* - Close the connection to the server. The servers we've created so far all are based - on the ACE_Reactor. When we close(), the server's reactor will see activity for - the registered event handler and invoke handle_input(). That, in turn, will try - to read from the socket but get back zero bytes. At that point, the server will know - that we've closed from our side. - */ - if (server.close () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1); - } - - return 0; -}</PRE> - -<HR WIDTH="100%"> - -<P>Ok, so that was pretty easy. What would be even easier would be to wrap -all of the connection mess up in an object and overload a couple of basic -operators to make things less network-centric. Perhaps we'll see that in -another tutorial. - -<P>If you want to compile it yourself, here's the <A HREF="client.cpp">source</A>, -the <A HREF="Makefile">Makefile</A>, -and <A HREF="00SetEnv">Environment -settings</A>. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/004/00SetEnv b/docs/tutorials/004/00SetEnv deleted file mode 100644 index eca78e10c85..00000000000 --- a/docs/tutorials/004/00SetEnv +++ /dev/null @@ -1,2 +0,0 @@ -export ACE_ROOT=/local/src/ACE/ACE_wrappers -export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH diff --git a/docs/tutorials/004/Makefile b/docs/tutorials/004/Makefile deleted file mode 100644 index 06940b7f6c4..00000000000 --- a/docs/tutorials/004/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -# -# Makefile for client logging applications -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = client - -LSRC = $(addsuffix .cpp,$(BIN)) - -VLDLIBS = $(LDLIBS:%=%$(VAR)) - -BUILD = $(VBIN) - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - diff --git a/docs/tutorials/004/client.cpp b/docs/tutorials/004/client.cpp deleted file mode 100644 index b32a5f8acb5..00000000000 --- a/docs/tutorials/004/client.cpp +++ /dev/null @@ -1,264 +0,0 @@ - -// $Id$ - -/* - We need the connector object & we also bring in a simple string class. - */ -#include "ace/SOCK_Connector.h" -#include "ace/SString.h" - -/* - In this tutorial, we extend SOCK_Stream by adding a few wrappers - around the send_n() method. - */ -class Client : public ACE_SOCK_Stream -{ - -public: - // Basic constructor - Client(void); - - /* - Construct and open() in one call. This isn't generally a good - idea because you don't have a clean way to inform the caller - when open() fails. (Unless you use C++ exceptions.) - */ - Client( const char * server, u_short port ); - - /* - Open the connection to the server. Notice that this mirrors - the use of ACE_SOCK_Connector. By providing our own open(), - we can hide the connector from our caller & make it's interaction - easier. - */ - int open( const char * server, u_short port ); - - /* - These are necessary if you're going to use the constructor that - invokes open(). - */ - inline int initialized(void) { return initialized_; } - inline int error(void) { return error_; } - - /* - This is where the coolness lies. Most C++ folks are familiar - with "cout << some-data". It's a very handy and easy way to - toss data around. By adding these method calls, we're able - to do the same thing with a socket connection. - */ - Client & operator<<( ACE_SString & str ); - Client & operator<<( char * str ); - Client & operator<<( int n ); - -protected: - unsigned char initialized_; - unsigned char error_; - -}; - -/* - The basic constructor just sets our flags to reasonable values. - */ -Client::Client(void) -{ - initialized_ = 0; - error_ = 0; -} - -/* - This constructor also sets the flags but then calls open(). If the - open() fails, the flags will be set appropriately. Use the two inline - method calls initialized() and error() to check the object state after - using this constructor. - */ -Client::Client( const char * server, u_short port ) -{ - initialized_ = 0; - error_ = 0; - (void)open(server,port); -} - -/* - Open a connection to the server. This hides the use of ACE_SOCK_Connector - from our caller. Since our caller probably doesn't care *how* we connect, - this is a good thing. - */ -int Client::open( const char * server, u_short port ) -{ - /* - This is right out of Tutorial 3. The only thing we've added is to set - the initialized_ member variable on success. - */ - - ACE_SOCK_Connector connector; - ACE_INET_Addr addr (port, server); - - if (connector.connect (*this, addr) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - initialized_ = 1; - - return(0); -} - -/* - The first of our put operators sends a simple string object to the peer. -*/ -Client & Client::operator<<( ACE_SString & str ) -{ - /* - We have to be able to allow: - server << foo << bar << stuff; - - To accomplish that, every << operator must check that the object is - in a valid state before doing work. - */ - - if( initialized() && ! error() ) - { - /* - Get the actual data held in the string object - */ - char * cp = str.rep(); - - /* - Send that data to the peer using send_n() as before. If we have - a problem, we'll set error_ so that subsequent << operations won't - try to use a broken stream. - */ - if( this->send_n(cp,strlen(cp)) == -1 ) - { - error_ = 1; - } - } - else - { - /* - Be sure that error_ is set if somebody tries to use us when - we're not initialized. - */ - error_ = 1; - } - - /* - We have to return a reference to ourselves to allow chaining of - put operations (eg -- "server << foo << bar"). Without the reference, - you would have to do each put operation as a statement. That's OK - but doesn't have the same feel as standard C++ iostreams. - */ - return *this ; -} - -/* -How do you put a char*? We'll take an easy way out and construct an ACE_SString -from the char* and then put that. It would have been more efficient to implement -this with the body of the operator<<(ACE_SString&) method and then express that -method in terms of this one. There's always more than one way to do things! - */ -Client & Client::operator<< ( char * str ) -{ - ACE_SString newStr(str); - - *this << newStr; - - return *this ; - - /* - Notice that we could have been really clever and done: - - return *this << ACE_SString(str); - - That kind of thing just makes debugging a pain though! - */ -} - -/* - ACE_SString and char* are both about the same thing. What do you do about - different datatypes though? - - Do the same thing we did with char* and convert it to ACE_SString where we - already have a << operator defined. - */ -Client & Client::operator<< ( int n ) -{ - /* - Create a character buffer large enough for the largest number. That's - a tough call but 1024 should be quite enough. - */ - char buf[1024]; - - /* - Put the number into our buffer... - */ - ACE_OS::sprintf(buf,"(%d)\n",n); - - /* - And create the ACE_SString that we know how to put. - */ - ACE_SString newStr(buf); - - /* - Send it and... - */ - *this << newStr; - - /* - return ourselves as usual. - */ - return *this; -} - - -/* - Now we pull it all together. Like Tutorial 3, we'll allow command line options. - */ -int main (int argc, char *argv[]) -{ - const char *server_host = argc > 1 ? argv[1] : ACE_DEFAULT_SERVER_HOST; - u_short server_port = argc > 2 ? ACE_OS::atoi (argv[2]) : ACE_DEFAULT_SERVER_PORT; - int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : 4; - - /* - Use the basic constructor since the other isn't really very safe. - */ - Client server; - - /* - Open the server connection. Notice how this is simpler than Tutorial 3 - since we only have to provide a host name and port value. - */ - if( server.open(server_host,server_port) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - for (int i = 0; i < max_iterations; i++) - { - /* - Tell the server which iteration we're on. No more mucking aroudn with - sprintf at this level! It's all hidden from us. - */ - server << "message = " << i+1; - - /* - Everything OK? - */ - if ( server.error() ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - else - { - ACE_OS::sleep (1); - } - } - - if (server.close () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1); - } - - return 0; -} diff --git a/docs/tutorials/004/page01.html b/docs/tutorials/004/page01.html deleted file mode 100644 index a6e69c5eb98..00000000000 --- a/docs/tutorials/004/page01.html +++ /dev/null @@ -1,316 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 004</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 004</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>A much more clever Client</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Ok, so the last time around, we learned how to create a simple client -that can send a chunk of data. A cooler thing to do is to overload -the C++ put operator (<<) to put some data for us. That's what -we're going to do this time. (This tutorial is actually where ACE_IOStream -was born.) - -<P> -<HR WIDTH="100%"> -<PRE>/* - We need the connector object & we also bring in a simple string class. - */ -#include "ace/SOCK_Connector.h" -#include "ace/SString.h" - -/* - In this tutorial, we extend SOCK_Stream by adding a few wrappers - around the send_n() method. - */ -class Client : public ACE_SOCK_Stream -{ - -public: - // Basic constructor - Client(void); - - /* - Construct and open() in one call. This isn't generally a good - idea because you don't have a clean way to inform the caller - when open() fails. (Unless you use C++ exceptions.) - */ - Client( const char * server, u_short port ); - - /* - Open the connection to the server. Notice that this mirrors - the use of ACE_SOCK_Connector. By providing our own open(), - we can hide the connector from our caller & make it's interaction - easier. - */ - int open( const char * server, u_short port ); - - /* - These are necessary if you're going to use the constructor that - invokes open(). - */ - inline int initialized(void) { return initialized_; } - inline int error(void) { return error_; } - - /* - This is where the coolness lies. Most C++ folks are familiar - with "cout << some-data". It's a very handy and easy way to - toss data around. By adding these method calls, we're able - to do the same thing with a socket connection. - */ - Client & operator<<( ACE_SString & str ); - Client & operator<<( char * str ); - Client & operator<<( int n ); - -protected: - unsigned char initialized_; - unsigned char error_; - -}; - -/* - The basic constructor just sets our flags to reasonable values. - */ -Client::Client(void) -{ - initialized_ = 0; - error_ = 0; -} - -/* - This constructor also sets the flags but then calls open(). If the - open() fails, the flags will be set appropriately. Use the two inline - method calls initialized() and error() to check the object state after - using this constructor. - */ -Client::Client( const char * server, u_short port ) -{ - initialized_ = 0; - error_ = 0; - (void)open(server,port); -} - -/* - Open a connection to the server. This hides the use of ACE_SOCK_Connector - from our caller. Since our caller probably doesn't care *how* we connect, - this is a good thing. - */ -int Client::open( const char * server, u_short port ) -{ - /* - This is right out of Tutorial 3. The only thing we've added is to set - the initialized_ member variable on success. - */ - - ACE_SOCK_Connector connector; - ACE_INET_Addr addr (port, server); - - if (connector.connect (*this, addr) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - initialized_ = 1; - - return(0); -} - -/* - The first of our put operators sends a simple string object to the peer. -*/ -Client & Client::operator<<( ACE_SString & str ) -{ - /* - We have to be able to allow: - server << foo << bar << stuff; - - To accomplish that, every << operator must check that the object is - in a valid state before doing work. - */ - - if( initialized() && ! error() ) - { - /* - Get the actual data held in the string object - */ - char * cp = str.rep(); - - /* - Send that data to the peer using send_n() as before. If we have - a problem, we'll set error_ so that subsequent << operations won't - try to use a broken stream. - */ - if( this->send_n(cp,strlen(cp)) == -1 ) - { - error_ = 1; - } - } - else - { - /* - Be sure that error_ is set if somebody tries to use us when - we're not initialized. - */ - error_ = 1; - } - - /* - We have to return a reference to ourselves to allow chaining of - put operations (eg -- "server << foo << bar"). Without the reference, - you would have to do each put operation as a statement. That's OK - but doesn't have the same feel as standard C++ iostreams. - */ - return *this ; -} - -/* -How do you put a char*? We'll take an easy way out and construct an ACE_SString -from the char* and then put that. It would have been more efficient to implement -this with the body of the operator<<(ACE_SString&) method and then express that -method in terms of this one. There's always more than one way to do things! - */ -Client & Client::operator<< ( char * str ) -{ - ACE_SString newStr(str); - - *this << newStr; - - return *this ; - - /* - Notice that we could have been really clever and done: - - return *this << ACE_SString(str); - - That kind of thing just makes debugging a pain though! - */ -} - -/* - ACE_SString and char* are both about the same thing. What do you do about - different datatypes though? - - Do the same thing we did with char* and convert it to ACE_SString where we - already have a << operator defined. - */ -Client & Client::operator<< ( int n ) -{ - /* - Create a character buffer large enough for the largest number. That's - a tough call but 1024 should be quite enough. - */ - char buf[1024]; - - /* - Put the number into our buffer... - */ - ACE_OS::sprintf(buf,"(%d)\n",n); - - /* - And create the ACE_SString that we know how to put. - */ - ACE_SString newStr(buf); - - /* - Send it and... - */ - *this << newStr; - - /* - return ourselves as usual. - */ - return *this; -} - - -/* - Now we pull it all together. Like Tutorial 3, we'll allow command line options. - */ -int main (int argc, char *argv[]) -{ - const char *server_host = argc > 1 ? argv[1] : ACE_DEFAULT_SERVER_HOST; - u_short server_port = argc > 2 ? ACE_OS::atoi (argv[2]) : ACE_DEFAULT_SERVER_PORT; - int max_iterations = argc > 3 ? ACE_OS::atoi (argv[3]) : 4; - - /* - Use the basic constructor since the other isn't really very safe. - */ - Client server; - - /* - Open the server connection. Notice how this is simpler than Tutorial 3 - since we only have to provide a host name and port value. - */ - if( server.open(server_host,server_port) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - for (int i = 0; i < max_iterations; i++) - { - /* - Tell the server which iteration we're on. No more mucking aroudn with - sprintf at this level! It's all hidden from us. - */ - server << "message = " << i+1; - - /* - Everything OK? - */ - if ( server.error() ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - else - { - ACE_OS::sleep (1); - } - } - - if (server.close () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "close"), -1); - } - - return 0; -}</PRE> - -<HR WIDTH="100%"> - -<P>Ok, now we're done with that. As you can see, it really isn't -so hard to create an object that makes sending data much more "natural" -than the typical send() or send_n() invocation. You can even build -up arbitrary objects & do some neat tricks with C++ templates to stream -their data out as well. (We may go into that a little later.) -Of course, writting the full implementation such that these streams are -interchangable with the standard C++ ostreams is quite a bit more difficult. -In addition, there are a lot of optimizations that this client would benefit -from! - -<P>As an exercise to the reader (don't you hate those!) I challenge you -to write the server side of this. You can take a look at IOStream_Test -in the ACE distribution if you get stuck... - -<P>If you want to compile it yourself, here's the <A HREF="client.cpp">source</A>, -the <A HREF="Makefile">Makefile</A>, -and <A HREF="00SetEnv">Environment -settings</A>. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/005/00SetEnv b/docs/tutorials/005/00SetEnv deleted file mode 100644 index eca78e10c85..00000000000 --- a/docs/tutorials/005/00SetEnv +++ /dev/null @@ -1,2 +0,0 @@ -export ACE_ROOT=/local/src/ACE/ACE_wrappers -export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH diff --git a/docs/tutorials/005/Makefile b/docs/tutorials/005/Makefile deleted file mode 100644 index 6c4b01dbf9c..00000000000 --- a/docs/tutorials/005/Makefile +++ /dev/null @@ -1,99 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -# You can generally find a Makefile in the ACE examples, tests or the library -# itself that will satisfy our application needs. This one was taken from -# one of the examples. - - # Define the name of the binary we want to create. There has to be - # a CPP file $(BIN).cpp but it doesn't necessarily have to have your - # main() in it. Most of the time, though, it will. -BIN = server - - # Few applications will have a single source file. We use the FILES - # macro to build up a list of additional files to compile. Notice - # that we leave off the extension just as with BIN -FILES = -FILES += client_handler - - # The BUILD macro is used by the ACE makefiles. Basically, it tells - # the system what to build. I don't really know what VBIN is other - # than it is constructed from the value of BIN. Just go with it... -BUILD = $(VBIN) - - # Here we use some GNU make extensions to build the SRC macro. Basically, - # we're just adding .cpp to the value of BIN and for each entry of the - # FILES macro. -SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES)) - - # This is used by my Indent target below. It's not a part of standard - # ACE and you don't need it yourself. -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - - # This is where the real power lies! These included makefile components - # are similar to the C++ templates in ACE. That is, they do a tremendous - # amount of work for you and all you have to do is include them. - # As a matter of fact, in our project, I created a single file named - # "app.mk" that includes all of these. Our project makefiles then just - # need to include app.mk to get everything they need. - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - - # Sometimes I like to reformat my code to make it more readable. This is - # more useful for the comments than anything else. Unfortunately, the - # "indent" program doesn't quite grok C++ so I have to post-process it's - # output just a bit. -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - - # One of the targets in the ACE makefiles is "depend". It will invoke - # your compiler in a way that will generate a list of dependencies for - # you. This is a great thing! Unfortunately, it puts all of that mess - # directly into the Makefile. I prefer my Makefile to stay clean and - # uncluttered. The perl script referenced here pulls the dependency - # stuff back out of the Makefile and into a file ".depend" which we then - # include just like the makefile components above. -Depend : depend - perl fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - - # Don't put anything below here. Between the "depend" target and fix.Makefile - # it's guaranteed to be lost! - - # This is inserted by the fix.Makefile script -include .depend diff --git a/docs/tutorials/005/acceptor b/docs/tutorials/005/acceptor deleted file mode 100644 index 45409e4ec3e..00000000000 --- a/docs/tutorials/005/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/005/client_acceptor.h b/docs/tutorials/005/client_acceptor.h deleted file mode 100644 index fa3d3b41be8..00000000000 --- a/docs/tutorials/005/client_acceptor.h +++ /dev/null @@ -1,45 +0,0 @@ - -// $Id$ - -#ifndef CLIENT_ACCEPTOR_H -#define CLIENT_ACCEPTOR_H - -/* - The ACE_Acceptor<> template lives in the ace/Acceptor.h header file. You'll - find a very consitent naming convention between the ACE objects and the - headers where they can be found. In general, the ACE object ACE_Foobar will - - - be found in ace/Foobar.h. - */ - -#include "ace/Acceptor.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -/* - Since we want to work with sockets, we'll need a SOCK_Acceptor to allow the - clients to connect to us. - */ -#include "ace/SOCK_Acceptor.h" - -/* - The Client_Handler object we develop will be used to handle clients once - they're connected. The ACE_Acceptor<> template's first parameter requires - such an object. In some cases, you can get by with just a forward - declaration on the class, in others you have to have the whole thing. - */ -#include "client_handler.h" - -/* - Parameterize the ACE_Acceptor<> such that it will listen for socket - connection attempts and create Client_Handler objects when they happen. In - Tutorial 001, we wrote the basic acceptor logic on our own before we - realized that ACE_Acceptor<> was available. You'll get spoiled using the - ACE templates because they take away a lot of the tedious details! - */ -typedef ACE_Acceptor < Client_Handler, ACE_SOCK_ACCEPTOR > Client_Acceptor; - -#endif // CLIENT_ACCEPTOR_H diff --git a/docs/tutorials/005/client_handler.cpp b/docs/tutorials/005/client_handler.cpp deleted file mode 100644 index 42c1b29d66f..00000000000 --- a/docs/tutorials/005/client_handler.cpp +++ /dev/null @@ -1,233 +0,0 @@ - -// $Id$ - -/* - In client_handler.h I alluded to the fact that we'll mess around with a - Client_Acceptor pointer. To do so, we need the Client_Acceptor object - declaration. - - We know that including client_handler.h is redundant because - client_acceptor.h includes it. Still, the sentry prevents double-inclusion - from causing problems and it's sometimes good to be explicit about what - we're using. - - On the other hand, we don't directly include any ACE header files here. - */ -#include "client_acceptor.h" -#include "client_handler.h" - -/* - Our constructor doesn't do anything. That's generally a good idea. Unless - you want to start throwing exceptions, there isn't a really good way to - indicate that a constructor has failed. If I had my way, I'd have a boolean - return code from it that would cause new to return 0 if I failed. Oh - well... - */ -Client_Handler::Client_Handler (void) -{ -} - -/* - Our destructor doesn't do anything either. That is also by design. - Remember, we really want folks to use destroy() to get rid of us. If that's - so, then there's nothing left to do when the destructor gets invoked. - */ -Client_Handler::~Client_Handler (void) -{ -} - -/* - The much talked about destroy() method! The reason I keep going on about - this is because it's just a Bad Idea (TM) to do real work inside of a - destructor. Although this method is void, it really should return - int so that it can tell the caller there was a problem. Even as - void you could at least throw an exception which you would never want - to do in a destructor. - */ -void Client_Handler::destroy (void) -{ - /* - We probably got here because of an error on the stream, so the peer - connection is probably already closed. Still... there are other ways to - get here and closing a closed peer doesn't hurt. - */ - this->peer ().close (); - - /* - Tell the reactor to forget all about us. Notice that we use the same args - here that we use in the open() method to register ourselves. In addition, - we use the DONT_CALL flag to prevent handle_close() being called. Since we - likely got here due to handle_close(), that could cause a bit of nasty - recursion! - */ - this->reactor ()->remove_handler (this, - ACE_Event_Handler:: READ_MASK | ACE_Event_Handler::DONT_CALL); - - /* - This is how we're able to tell folks not to use delete. By - deleting our own instance, we take care of memory leaks after ensuring - that the object is shut down correctly. - */ - delete this; -} - -/* - As mentioned before, the open() method is called by the Client_Acceptor when - a new client connection has been accepted. The Client_Acceptor instance - pointer is cast to a void* and given to us here. We'll use that to avoid - some global data... - */ -int Client_Handler::open (void *_acceptor) -{ - /* - Convert the void* to a Client_Acceptor*. You should probably use those - fancy new C++ cast operators but I can never remember how/when to do so. - Since you can cast just about anything around a void* without compiler - warnings be very sure of what you're doing when you do this kind of thing. - That's where the new-style cast operators can save you. - */ - Client_Acceptor *acceptor = (Client_Acceptor *) _acceptor; - - /* - Our reactor reference will be set when we register ourselves but I decided - to go ahead and set it here. No good reason really... - */ - this->reactor (acceptor->reactor ()); - - /* - We need this to store the address of the client that we are now connected - to. We'll use it later to display a debug message. - */ - ACE_INET_Addr addr; - - /* - Our ACE_Svc_Handler baseclass gives us the peer() method as a way to - access our underlying ACE_SOCK_Stream. On that object, we can invoke the - get_remote_addr() method to get get an ACE_INET_Addr having our client's - address information. As with most ACE methods, we'll get back (and return) - a -1 if there was any kind of error. Once we have the ACE_INET_Addr, we - can query it to find out the clien's host name, TCP/IP address, TCP/IP - port value and so forth. One word of warning: the get_host_name() - method of ACE_INET_Addr may return you an empty string if your name server - can't resolve it. On the other hand, get_host_addr() will always give you - the dotted-decimal string representing the TCP/IP address. - */ - if (this->peer ().get_remote_addr (addr) == -1) - { - return -1; - } - - /* - If we managed to get the client's address then we're connected to a real - and valid client. I suppose that in some cases, the client may connect - and disconnect so quickly that it is invalid by the time we get here. In - any case, the test above should always be done to ensure that the - connection is worth keeping. - - Now, regiser ourselves with a reactor and tell that reactor that we want - to be notified when there is something to read. Remember, we took our - reactor value from the acceptor which created us in the first place. - Since we're exploring a single-threaded implementation, this is the - correct thing to do. - */ - if (this->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, we use the ACE_INET_Addr object to print a message with the name of - the client we're connected to. Again, it is possible that you'll get an - empty string for the host name if your DNS isn't configured correctly or - if there is some other reason that a TCP/IP addreess cannot be converted - into a host name. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name ())); - - /* - Always return zero on success. - */ - return 0; -} - -/* - In the open() method, we registered with the reactor and requested to be - notified when there is data to be read. When the reactor sees that activity - it will invoke this handle_input() method on us. As I mentioned, the _handle - parameter isn't useful to us but it narrows the list of methods the reactor - has to worry about and the list of possible virtual functions we would have - to override. - */ -int Client_Handler::handle_input (ACE_HANDLE _handle) -{ - /* - Some compilers don't like it when you fail to use a parameter. This macro - will keep 'em quiet for you. - */ - ACE_UNUSED_ARG (_handle); - - /* - Now, we create and initialize a buffer for receiving the data. Since this - is just a simple test app, we'll use a small buffer size. - */ - char buf[128]; - ACE_OS::memset (buf, 0, sizeof (buf)); - - /* - Invoke the process() method with a pointer to our data area. We'll let - that method worry about interfacing with the data. You might choose to go - ahead and read the data and then pass the result to process(). However, - application logic may require that you read a few bytes to determine what - else to read... It's best if we push that all into the application-logic - level. - */ - return this->process (buf, sizeof (buf)); -} - -/* - If we return -1 out of handle_input() or if the reactor sees other problems - with us then handle_close() will be called. It uses our destroy() method to - shut us down cleanly and get rid of our instance. - */ -int Client_Handler::handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask) -{ - ACE_UNUSED_ARG (_handle); - ACE_UNUSED_ARG (_mask); - - this->destroy (); - return 0; -} - -/* - And, at last, we get to the application-logic level. Out of everything - we've done so far, this is the only thing that really has anything to do - with what your application will do. In this method we will read and process - the client's data. In a real appliation, you will probably have a bit more - in main() to deal with command line options but after that point, all of the - action takes place here. - */ -int Client_Handler::process (char *_rdbuf, int _rdbuf_len) -{ - /* - Using the buffer provided for us, we read the data from the client. If - there is a read error (eg -- recv() returns -1) then it's a pretty good - bet that the connection is gone. Likewise, if we read zero bytes then - something wrong has happened. The reactor wouldn't have called us if - there wasn't some kind of read activity but there wouldn't be activity if - there were no bytes to read... - - On the other hand, if we got some data then we can display it in a debug - message for everyone to see. - */ - switch (this->peer ().recv (_rdbuf, _rdbuf_len)) - { - case -1: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1); - case 0: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), -1); - default: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf)); - } - - return 0; -} diff --git a/docs/tutorials/005/client_handler.h b/docs/tutorials/005/client_handler.h deleted file mode 100644 index b1e4af021d3..00000000000 --- a/docs/tutorials/005/client_handler.h +++ /dev/null @@ -1,108 +0,0 @@ - -// $Id$ - -#ifndef CLIENT_HANDLER_H -#define CLIENT_HANDLER_H - -/* - Our client handler must exist somewhere in the ACE_Event_Handler object - hierarchy. This is a requirement of the ACE_Reactor because it maintains - ACE_Event_Handler pointers for each registered event handler. You could - derive our Client_Handler directly from ACE_Event_Handler but you still have - to have an ACE_SOCK_Stream for the actually connection. With a direct - derivative of ACE_Event_Handler, you'll have to contain and maintain an - ACE_SOCK_Stream instance yourself. With ACE_Svc_Handler (which is a - derivative of ACE_Event_Handler) some of those details are handled for you. - - */ - -#include "ace/Svc_Handler.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "ace/SOCK_Stream.h" - -/* - Another feature of ACE_Svc_Handler is it's ability to present the ACE_Task<> - interface as well. That's what the ACE_NULL_SYNCH parameter below is all - about. That's beyond our scope here but we'll come back to it in the next - tutorial when we start looking at concurrency options. - */ -class Client_Handler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > -{ -public: - - // Constructor... - Client_Handler (void); - - /* - The destroy() method is our preferred method of destruction. We could - have overloaded the delete operator but that is neither easy nor - intuitive (at least to me). Instead, we provide a new method of - destruction and we make our destructor protected so that only ourselves, - our derivatives and our friends can delete us. It's a nice - compromise. - */ - void destroy (void); - - /* - Most ACE objects have an open() method. That's how you make them ready - to do work. ACE_Event_Handler has a virtual open() method which allows us - to create this overrride. ACE_Acceptor<> will invoke this method after - creating a new Client_Handler when a client connects. Notice that the - parameter to open() is a void*. It just so happens that the pointer - points to the acceptor which created us. You would like for the parameter - to be an ACE_Acceptor<>* but since ACE_Event_Handler is generic, that - would tie it too closely to the ACE_Acceptor<> set of objects. In our - definition of open() you'll see how we get around that. - */ - int open (void *_acceptor); - - /* - When there is activity on a registered handler, the handle_input() method - of the handler will be invoked. If that method returns an error code (eg - -- -1) then the reactor will invoke handle_close() to allow the object to - clean itself up. Since an event handler can be registered for more than - one type of callback, the callback mask is provided to inform - handle_close() exactly which method failed. That way, you don't have to - maintain state information between your handle_* method calls. The _handle - parameter is explained below... - */ - int handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask); - -protected: - - /* - When we register with the reactor, we're going to tell it that we want to - be notified of READ events. When the reactor sees that there is read - activity for us, our handle_input() will be invoked. The _handleg - provided is the handle (file descriptor in Unix) of the actual connection - causing the activity. Since we're derived from ACE_Svc_Handler<> and it - maintains it's own peer (ACE_SOCK_Stream) object, this is redundant for - us. However, if we had been derived directly from ACE_Event_Handler, we - may have chosen not to contain the peer. In that case, the _handleg - would be important to us for reading the client's data. - */ - int handle_input (ACE_HANDLE _handle); - - /* - This has nothing at all to do with ACE. I've added this here as a worker - function which I will call from handle_input(). That allows me to - introduce concurrencly in later tutorials with a no changes to the worker - function. You can think of process() as application-level code and - everything elase as application-framework code. - */ - int process (char *_rdbuf, int _rdbuf_len); - - /* - We don't really do anything in our destructor but we've declared it to be - protected to prevent casual deletion of this object. As I said above, I - really would prefer that everyone goes through the destroy() method to get - rid of us. - */ - ~Client_Handler (void); -}; - -#endif // CLIENT_HANDLER_H diff --git a/docs/tutorials/005/fix.Makefile b/docs/tutorials/005/fix.Makefile deleted file mode 100644 index e99c194114a..00000000000 --- a/docs/tutorials/005/fix.Makefile +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/perl - - # Open the Makefile that has been mangled by 'make depend' - # and suck it into a perl array. -open(IF,"<Makefile") || die; -@makefile = <IF>; -close(IF); - - # Now open our .depend file and a temporary Makefile. - # We'll split the original Makefile between these two. -open(DF,">.depend") || die; -open(MF,">Makefile.tmp") || die; - - # For each line we read out of the original file... -foreach (@makefile) { - - # If we're into the dependency section, write the line - # into the .depend file. - # - if( $depend ) { - print DF $_; - } - else { - # If we haven't gotten to the dependency section yet - # then see if the current line is the separator that - # "make depend" causes to be inserted. - # - if( m/^\Q# DO NOT DELETE THIS LINE -- g++dep uses it.\E/ ) { - - # If so, change our "mode" and skip this line. - ++$depend; - next; - } - - # Also skip the "include .depend" that we insert. If we - # don't do this, it is possible to have a bunch of these - # inserted into the output when we read an unmangled Makefile - next if( m/^include .depend/ ); - - # Print the non-dependency info to the temporary Makefile - print MF $_; - } -} - -# Tell our new Makefile to include the dependency file -print MF "include .depend\n"; - -# Close the two output files... -close(DF); -close(MF); - -# Unlink (remove) the original Makefile and rename our -# temporary file. There's obviously room for error checking -# here but we've got the Makefile checked into some revision -# control system anyway. Don't we? - -unlink("Makefile"); -rename("Makefile.tmp","Makefile"); - -exit(0); diff --git a/docs/tutorials/005/handler b/docs/tutorials/005/handler deleted file mode 100644 index d987f4c34ff..00000000000 --- a/docs/tutorials/005/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/005/main b/docs/tutorials/005/main deleted file mode 100644 index 36c67561463..00000000000 --- a/docs/tutorials/005/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/005/page01.html b/docs/tutorials/005/page01.html deleted file mode 100644 index 60ae178abf3..00000000000 --- a/docs/tutorials/005/page01.html +++ /dev/null @@ -1,38 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In this tutorial, we're going to flash-back to the simple server we -created a while back. We'll create a very simple server where everything -takes place in one thread. Once we have a solid understanding there, -we'll move on to the next tutorial where we begin to introduce concurrency -concepts. - -<P>There are four C++ source files in this tutorial: server.cpp, -client_acceptor.h, client_handler.h and client_handler.cpp. I'll -talk about each of these in turn with the usual color commentary as we -go. In addition, I'll briefly discuss the Makefile and a short perl -script I've added. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/005/page02.html b/docs/tutorials/005/page02.html deleted file mode 100644 index 7d268e8bd00..00000000000 --- a/docs/tutorials/005/page02.html +++ /dev/null @@ -1,201 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>We begin with <I><A HREF="server.cpp">server.cpp</A></I>. - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: server.cpp,v 1.5 1998/08/29 21:57:32 -jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We try to keep main() very -simple. One of the ways we do that is to push</FONT> -<BR><FONT FACE="Arial,Helvetica"> much of the complicated stuff -into worker objects. In this case, we only</FONT> -<BR><FONT FACE="Arial,Helvetica"> need to include the acceptor -header in our main source file. We let it</FONT> -<BR><FONT FACE="Arial,Helvetica"> worry about the "real work".</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As before, we create a simple -signal handler that will set our finished</FONT> -<BR><FONT FACE="Arial,Helvetica"> flag. There are, of -course, more elegant ways to handle program shutdown</FONT> -<BR><FONT FACE="Arial,Helvetica"> requests but that isn't really -our focus right now, so we'll just do the</FONT> -<BR><FONT FACE="Arial,Helvetica"> easiest thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">static sig_atomic_t finished = 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">extern "C" void handler (int)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> finished = 1;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> A server has to listen for -clients at a known TCP/IP port. The default ACE</FONT> -<BR><FONT FACE="Arial,Helvetica"> port is 10002 (at least on -my system) and that's good enough for what we</FONT> -<BR><FONT FACE="Arial,Helvetica"> want to do here. Obviously, -a more robust application would take a command</FONT> -<BR><FONT FACE="Arial,Helvetica"> line parameter or read from -a configuration file or do some other clever</FONT> -<BR><FONT FACE="Arial,Helvetica"> thing. Just like the -signal handler above, though, that's what we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> focus on, so we're taking -the easy way out.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Finally, we get to main. -Some C++ compilers will complain loudly if your</FONT> -<BR><FONT FACE="Arial,Helvetica"> function signature doesn't -match the prototype. Even though we're not</FONT> -<BR><FONT FACE="Arial,Helvetica"> going to use the parameters, -we still have to specify them.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">int main (int argc, char *argv[])</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In our earlier servers, we -used a global pointer to get to the reactor. I've</FONT> -<BR><FONT FACE="Arial,Helvetica"> never really liked that idea, -so I've moved it into main() this time. When</FONT> -<BR><FONT FACE="Arial,Helvetica"> we get to the Client_Handler -object you'll see how we manage to get a</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer back to this reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Reactor reactor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The acceptor -will take care of letting clients connect to us. It will</FONT> -<BR><FONT FACE="Arial,Helvetica"> also arrange -for a Client_Handler to be created for each new client.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we're only -going to listen at one TCP/IP port, we only need one</FONT> -<BR><FONT FACE="Arial,Helvetica"> acceptor. -If we wanted, though, we could create several of these and</FONT> -<BR><FONT FACE="Arial,Helvetica"> listen at several -ports. (That's what we would do if we wanted to rewrite</FONT> -<BR><FONT FACE="Arial,Helvetica"> inetd for -instance.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor peer_acceptor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Create an ACE_INET_Addr -that represents our endpoint of a connection. We</FONT> -<BR><FONT FACE="Arial,Helvetica"> then open our -acceptor object with that Addr. Doing so tells the acceptor</FONT> -<BR><FONT FACE="Arial,Helvetica"> where to listen -for connections. Servers generally listen at "well known"</FONT> -<BR><FONT FACE="Arial,Helvetica"> addresses. -If not, there must be some mechanism by which the client is</FONT> -<BR><FONT FACE="Arial,Helvetica"> informed of the -server's address.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Note how ACE_ERROR_RETURN -is used if we fail to open the acceptor. This</FONT> -<BR><FONT FACE="Arial,Helvetica"> technique is -used over and over again in our tutorials.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (peer_acceptor.open (ACE_INET_Addr -(PORT), &reactor) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN ((LM_ERROR, -"%p\n", "open"), -1);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Here, we know -that the open was successful. If it had failed, we would</FONT> -<BR><FONT FACE="Arial,Helvetica"> have exited above. -A nice side-effect of the open() is that we're already</FONT> -<BR><FONT FACE="Arial,Helvetica"> registered with -the reactor we provided it.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Install our signal -handler. You can actually register signal handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> with the reactor. -You might do that when the signal handler is</FONT> -<BR><FONT FACE="Arial,Helvetica"> responsible for -performing "real" work. Our simple flag-setter doesn't</FONT> -<BR><FONT FACE="Arial,Helvetica"> justify deriving -from ACE_Event_Handler and providing a callback function</FONT> -<BR><FONT FACE="Arial,Helvetica"> though.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Sig_Action sa ((ACE_SignalHandler) -handler, SIGINT);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Like ACE_ERROR_RETURN, -the ACE_DEBUG macro gets used quite a bit. It's a</FONT> -<BR><FONT FACE="Arial,Helvetica"> handy way to -generate uniform debug output from your program.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) -starting up server daemon\n"));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This will loop -"forever" invoking the handle_events() method of our</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor. handle_events() -watches for activity on any registered handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> and invokes their -appropriate callbacks when necessary. Callback-driven</FONT> -<BR><FONT FACE="Arial,Helvetica"> programming is -a big thing in ACE, you should get used to it. If the</FONT> -<BR><FONT FACE="Arial,Helvetica"> signal handler -catches something, the finished flag will be set and we'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> exit. Conveniently -enough, handle_events() is also interrupted by signals</FONT> -<BR><FONT FACE="Arial,Helvetica"> and will exit -back to the while() loop. (If you want your event loop to</FONT> -<BR><FONT FACE="Arial,Helvetica"> not be interrupted -by signals, checkout the <i>restart</i> flag on the</FONT> -<BR><FONT FACE="Arial,Helvetica"> open() method -of ACE_Reactor if you're interested.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> while (!finished)</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor.handle_events -();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting -down server daemon\n"));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page03.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/005/page03.html b/docs/tutorials/005/page03.html deleted file mode 100644 index fb8acc3e913..00000000000 --- a/docs/tutorials/005/page03.html +++ /dev/null @@ -1,94 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Now, let's take a look at <I><A HREF="client_acceptor.h">client_acceptor.h</A></I>. -Since I went on about how it does all the work of letting clients connect -to us, it must be rather complext. Right? Wrong. - -<P>The more you use ACE, the more you'll find that they've already taken -care of most details for you. With respect to the acceptance of client -connections: there just aren't that many ways to do it! The -ACE team has chosen an approach and created a C++ template that does -all of the work for you. All you're required to do is provide it -with an object type to instantiate when a new connection arrives. - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id$</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#ifndef CLIENT_ACCEPTOR_H</FONT> -<BR><FONT FACE="Arial,Helvetica">#define CLIENT_ACCEPTOR_H</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The ACE_Acceptor<> template lives -in the ace/Acceptor.h header file.</FONT> -<BR><FONT FACE="Arial,Helvetica"> You'll find a very consitent naming -convention between the ACE objects</FONT> -<BR><FONT FACE="Arial,Helvetica"> and the headers where they can be -found. In general, the ACE object</FONT> -<BR><FONT FACE="Arial,Helvetica"> <I>ACE_Foobar</I> will be found -in <I>ace/Foobar.h</I>.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "ace/Acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we want to work with sockets, -we'll need a SOCK_Acceptor to allow</FONT> -<BR><FONT FACE="Arial,Helvetica"> the clients to connect to us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "ace/SOCK_Acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The Client_Handler object we develop -will be used to handle clients</FONT> -<BR><FONT FACE="Arial,Helvetica"> once they're connected. The -ACE_Acceptor<> template's first parameter</FONT> -<BR><FONT FACE="Arial,Helvetica"> requires such an object. In -some cases, you can get by with just a</FONT> -<BR><FONT FACE="Arial,Helvetica"> forward declaration on the class, -in others you have to have the whole</FONT> -<BR><FONT FACE="Arial,Helvetica"> thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Parameterize the ACE_Acceptor<> -such that it will listen for socket</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection attempts and create Client_Handler -objects when they happen.</FONT> -<BR><FONT FACE="Arial,Helvetica"> In Tutorial 001, we wrote the basic -acceptor logic on our own before</FONT> -<BR><FONT FACE="Arial,Helvetica"> we realized that ACE_Acceptor<> -was available. You'll get spoiled using</FONT> -<BR><FONT FACE="Arial,Helvetica"> the ACE templates because they take -away a lot of the tedious details!</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">typedef ACE_Acceptor < Client_Handler, -ACE_SOCK_ACCEPTOR > Client_Acceptor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_ACCEPTOR_H</FONT> - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page04.html">Continue This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/005/page04.html b/docs/tutorials/005/page04.html deleted file mode 100644 index 2a526c22911..00000000000 --- a/docs/tutorials/005/page04.html +++ /dev/null @@ -1,192 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Ok, so we've got a main() loop that sets up the acceptor and we've seen -how easy it is to create the acceptor object. So far, we've hardly -written any code at all. Well, that's just about to change... - -<P>First, we look at <I><A HREF="client_handler.h">client_handler.h</A></I> -for the declaration of the Client_Handler object. Then we look at -the definition where all of the real work of the application takes place. - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id$</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#ifndef CLIENT_HANDLER_H</FONT> -<BR><FONT FACE="Arial,Helvetica">#define CLIENT_HANDLER_H</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our client handler must exist -somewhere in the ACE_Event_Handler object</FONT> -<BR><FONT FACE="Arial,Helvetica"> hierarchy. This is -a requirement of the ACE_Reactor because it maintains</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Event_Handler pointers -for each registered event handler. You could</FONT> -<BR><FONT FACE="Arial,Helvetica"> derive our Client_Handler -directly from ACE_Event_Handler but you still have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to have an ACE_SOCK_Stream -for the actually connection. With a direct</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler, -you'll have to contain and maintain an</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_SOCK_Stream instance -yourself. With ACE_Svc_Handler (which is a</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler) -some of those details are handled for you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "ace/Svc_Handler.h"</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "ace/SOCK_Stream.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Another feature of ACE_Svc_Handler -is it's ability to present the ACE_Task<></FONT> -<BR><FONT FACE="Arial,Helvetica"> interface as well. -That's what the ACE_NULL_SYNCH parameter below is all</FONT> -<BR><FONT FACE="Arial,Helvetica"> about. That's beyond -our scope here but we'll come back to it in the next</FONT> -<BR><FONT FACE="Arial,Helvetica"> tutorial when we start looking -at concurrency options.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Client_Handler : public ACE_Svc_Handler -< ACE_SOCK_STREAM, ACE_NULL_SYNCH ></FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">public:</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> // Constructor...</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The destroy() -method is our preferred method of destruction. We could</FONT> -<BR><FONT FACE="Arial,Helvetica"> have overloaded -the <i>delete</i> operator but that is neither easy nor</FONT> -<BR><FONT FACE="Arial,Helvetica"> intuitive (at -least to me). Instead, we provide a new method of</FONT> -<BR><FONT FACE="Arial,Helvetica"> destruction and -we make our destructor protected so that only ourselves,</FONT> -<BR><FONT FACE="Arial,Helvetica"> our derivatives -and our friends can <i>delete</i> us. It's a nice</FONT> -<BR><FONT FACE="Arial,Helvetica"> compromise.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> void destroy (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Most ACE objects -have an open() method. That's how you make them ready</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do work. -ACE_Event_Handler has a virtual open() method which allows us</FONT> -<BR><FONT FACE="Arial,Helvetica"> to create this -overrride. ACE_Acceptor<> will invoke this method after</FONT> -<BR><FONT FACE="Arial,Helvetica"> creating a new -Client_Handler when a client connects. Notice that the</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter to -open() is a void*. It just so happens that the pointer</FONT> -<BR><FONT FACE="Arial,Helvetica"> points to the -acceptor which created us. You would like for the parameter</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be an ACE_Acceptor<>* -but since ACE_Event_Handler is generic, that</FONT> -<BR><FONT FACE="Arial,Helvetica"> would tie it -too closely to the ACE_Acceptor<> set of objects. In our</FONT> -<BR><FONT FACE="Arial,Helvetica"> definition of -open() you'll see how we get around that.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int open (void *_acceptor);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When there is -activity on a registered handler, the handle_input() method</FONT> -<BR><FONT FACE="Arial,Helvetica"> of the handler -will be invoked. If that method returns an error code (eg</FONT> -<BR><FONT FACE="Arial,Helvetica"> -- -1) then the -reactor will invoke handle_close() to allow the object to</FONT> -<BR><FONT FACE="Arial,Helvetica"> clean itself -up. Since an event handler can be registered for more than</FONT> -<BR><FONT FACE="Arial,Helvetica"> one type of callback, -the callback mask is provided to inform</FONT> -<BR><FONT FACE="Arial,Helvetica"> handle_close() -exactly which method failed. That way, you don't have to</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintain state -information between your handle_* method calls. The _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter is -explained below...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int handle_close (ACE_HANDLE _handle, -ACE_Reactor_Mask _mask);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When we register -with the reactor, we're going to tell it that we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> be notified of -READ events. When the reactor sees that there is read</FONT> -<BR><FONT FACE="Arial,Helvetica"> activity for -us, our handle_input() will be invoked. The <i>_handle</i></FONT> -<BR><FONT FACE="Arial,Helvetica"> provided is the -handle (file descriptor in Unix) of the actual connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> causing the activity. -Since we're derived from ACE_Svc_Handler<> and it</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintains it's -own peer (ACE_SOCK_Stream) object, this is redundant for</FONT> -<BR><FONT FACE="Arial,Helvetica"> us. However, -if we had been derived directly from ACE_Event_Handler, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> may have chosen -not to contain the peer. In that case, the <i>_handle</i></FONT> -<BR><FONT FACE="Arial,Helvetica"> would be important -to us for reading the client's data.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int handle_input (ACE_HANDLE _handle);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This has nothing -at all to do with ACE. I've added this here as a worker</FONT> -<BR><FONT FACE="Arial,Helvetica"> function which -I will call from handle_input(). That allows me to</FONT> -<BR><FONT FACE="Arial,Helvetica"> introduce concurrencly -in later tutorials with a no changes to the worker</FONT> -<BR><FONT FACE="Arial,Helvetica"> function. -You can think of process() as application-level code and</FONT> -<BR><FONT FACE="Arial,Helvetica"> everything elase -as application-framework code.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int process (char *_rdbuf, int -_rdbuf_len);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We don't really -do anything in our destructor but we've declared it to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> protected to -prevent casual deletion of this object. As I said above, I</FONT> -<BR><FONT FACE="Arial,Helvetica"> really would -prefer that everyone goes through the destroy() method to get</FONT> -<BR><FONT FACE="Arial,Helvetica"> rid of us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ~Client_Handler (void);</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_HANDLER_H</FONT> - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/005/page05.html b/docs/tutorials/005/page05.html deleted file mode 100644 index 117366b5af3..00000000000 --- a/docs/tutorials/005/page05.html +++ /dev/null @@ -1,385 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Now we're finally at <I><A HREF="client_handler.cpp">client_handler.cpp</A></I> -where we have to write some code. This file has more code than the -rest of the application all together. - -<P> -<HR WIDTH="100%"> -<BR> -<BR> <FONT FACE="Arial,Helvetica">// $Id$</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In client_handler.h I alluded -to the fact that we'll mess around with a</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor pointer. -To do so, we need the Client_Acceptor object</FONT> -<BR><FONT FACE="Arial,Helvetica"> declaration.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> We know that including client_handler.h -is redundant because</FONT> -<BR><FONT FACE="Arial,Helvetica"> client_acceptor.h includes -it. Still, the sentry prevents double-inclusion</FONT> -<BR><FONT FACE="Arial,Helvetica"> from causing problems and -it's sometimes good to be explicit about what</FONT> -<BR><FONT FACE="Arial,Helvetica"> we're using.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> On the other hand, we don't -directly include any ACE header files here.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our constructor doesn't do -anything. That's generally a good idea. Unless</FONT> -<BR><FONT FACE="Arial,Helvetica"> you want to start throwing -exceptions, there isn't a really good way to</FONT> -<BR><FONT FACE="Arial,Helvetica"> indicate that a constructor -has failed. If I had my way, I'd have a boolean</FONT> -<BR><FONT FACE="Arial,Helvetica"> return code from it that -would cause <I>new</I> to return 0 if I failed. Oh</FONT> -<BR><FONT FACE="Arial,Helvetica"> well...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Handler::Client_Handler (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our destructor doesn't do -anything either. That is also by design.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Remember, we really want -folks to use destroy() to get rid of us. If that's</FONT> -<BR><FONT FACE="Arial,Helvetica"> so, then there's nothing -left to do when the destructor gets invoked.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Handler::~Client_Handler (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The much talked about destroy() -method! The reason I keep going on about</FONT> -<BR><FONT FACE="Arial,Helvetica"> this is because it's just -a Bad Idea (TM) to do real work inside of a</FONT> -<BR><FONT FACE="Arial,Helvetica"> destructor. Although -this method is <I>void</I>, it really should return</FONT> -<BR><FONT FACE="Arial,Helvetica"> <I>int</I> so that it can -tell the caller there was a problem. Even as</FONT> -<BR><FONT FACE="Arial,Helvetica"> <I>void</I> you could at -least throw an exception which you would never want</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do in a destructor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">void Client_Handler::destroy (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We probably got -here because of an error on the stream, so the peer</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection is -probably already closed. Still... there are other ways to</FONT> -<BR><FONT FACE="Arial,Helvetica"> get here and -closing a closed peer doesn't hurt.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->peer ().close ();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Tell the reactor -to forget all about us. Notice that we use the same args</FONT> -<BR><FONT FACE="Arial,Helvetica"> here that we -use in the open() method to register ourselves. In addition,</FONT> -<BR><FONT FACE="Arial,Helvetica"> we use the DONT_CALL -flag to prevent handle_close() being called. Since we</FONT> -<BR><FONT FACE="Arial,Helvetica"> likely got here -due to handle_close(), that could cause a bit of nasty</FONT> -<BR><FONT FACE="Arial,Helvetica"> recursion!</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->reactor ()->remove_handler -(this,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Event_Handler:: READ_MASK | ACE_Event_Handler::DONT_CALL);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This is how we're -able to tell folks not to use <I>delete</I>. By deleting</FONT> -<BR><FONT FACE="Arial,Helvetica"> our own instance, -we take care of memory leaks after ensuring</FONT> -<BR><FONT FACE="Arial,Helvetica"> that the object -is shut down correctly.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> delete this;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As mentioned before, the -open() method is called by the Client_Acceptor when</FONT> -<BR><FONT FACE="Arial,Helvetica"> a new client connection has -been accepted. The Client_Acceptor instance</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer is cast to a void* -and given to us here. We'll use that to avoid</FONT> -<BR><FONT FACE="Arial,Helvetica"> some global data...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::open (void *_acceptor)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Convert the void* -to a Client_Acceptor*. You should probably use those</FONT> -<BR><FONT FACE="Arial,Helvetica"> fancy new C++ -cast operators but I can never remember how/when to do so.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since you can -cast just about anything around a void* without compiler</FONT> -<BR><FONT FACE="Arial,Helvetica"> warnings be very -sure of what you're doing when you do this kind of thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> That's where -the new-style cast operators can save you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor *acceptor = (Client_Acceptor -*) _acceptor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our reactor reference -will be set when we register ourselves but I decided</FONT> -<BR><FONT FACE="Arial,Helvetica"> to go ahead and -set it here. No good reason really...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->reactor (acceptor->reactor -());</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We need this -to store the address of the client that we are now connected</FONT> -<BR><FONT FACE="Arial,Helvetica"> to. We'll -use it later to display a debug message.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_INET_Addr addr;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our ACE_Svc_Handler -baseclass gives us the peer() method as a way to</FONT> -<BR><FONT FACE="Arial,Helvetica"> access our underlying -ACE_SOCK_Stream. On that object, we can invoke the</FONT> -<BR><FONT FACE="Arial,Helvetica"> get_remote_addr() -method to get get an ACE_INET_Addr having our client's</FONT> -<BR><FONT FACE="Arial,Helvetica"> address information. -As with most ACE methods, we'll get back (and return)</FONT> -<BR><FONT FACE="Arial,Helvetica"> a -1 if there -was any kind of error. Once we have the ACE_INET_Addr, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> can query it -to find out the clien's host name, TCP/IP address, TCP/IP</FONT> -<BR><FONT FACE="Arial,Helvetica"> port value and -so forth. One word of warning: the get_host_name()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method of ACE_INET_Addr -may return you an empty string if your name server</FONT> -<BR><FONT FACE="Arial,Helvetica"> can't resolve -it. On the other hand, get_host_addr() will always give you</FONT> -<BR><FONT FACE="Arial,Helvetica"> the dotted-decimal -string representing the TCP/IP address.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (this->peer ().get_remote_addr -(addr) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return --1;</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If we managed -to get the client's address then we're connected to a real</FONT> -<BR><FONT FACE="Arial,Helvetica"> and valid client. -I suppose that in some cases, the client may connect</FONT> -<BR><FONT FACE="Arial,Helvetica"> and disconnect -so quickly that it is invalid by the time we get here. In</FONT> -<BR><FONT FACE="Arial,Helvetica"> any case, the -test above should always be done to ensure that the</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection is -worth keeping.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Now, regiser ourselves -with a reactor and tell that reactor that we want</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be notified -when there is something to read. Remember, we took our</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor value -from the acceptor which created us in the first place.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we're exploring -a single-threaded implementation, this is the</FONT> -<BR><FONT FACE="Arial,Helvetica"> correct thing -to do.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (this->reactor ()->register_handler -(this, ACE_Event_Handler::READ_MASK) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Here, we use -the ACE_INET_Addr object to print a message with the name of</FONT> -<BR><FONT FACE="Arial,Helvetica"> the client we're -connected to. Again, it is possible that you'll get an</FONT> -<BR><FONT FACE="Arial,Helvetica"> empty string -for the host name if your DNS isn't configured correctly or</FONT> -<BR><FONT FACE="Arial,Helvetica"> if there is some -other reason that a TCP/IP addreess cannot be converted</FONT> -<BR><FONT FACE="Arial,Helvetica"> into a host name.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) -connected with %s\n", addr.get_host_name ()));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Always return -zero on success.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In the open() method, we -registered with the reactor and requested to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> notified when there is data -to be read. When the reactor sees that activity</FONT> -<BR><FONT FACE="Arial,Helvetica"> it will invoke this handle_input() -method on us. As I mentioned, the _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter isn't useful to -us but it narrows the list of methods the reactor</FONT> -<BR><FONT FACE="Arial,Helvetica"> has to worry about and the -list of possible virtual functions we would have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to override.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::handle_input (ACE_HANDLE -_handle)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Some compilers -don't like it when you fail to use a parameter. This macro</FONT> -<BR><FONT FACE="Arial,Helvetica"> will keep 'em -quiet for you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_handle);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Now, we create -and initialize a buffer for receiving the data. Since this</FONT> -<BR><FONT FACE="Arial,Helvetica"> is just a simple -test app, we'll use a small buffer size.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, 0, sizeof (buf));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Invoke the process() -method with a pointer to our data area. We'll let</FONT> -<BR><FONT FACE="Arial,Helvetica"> that method worry -about interfacing with the data. You might choose to go</FONT> -<BR><FONT FACE="Arial,Helvetica"> ahead and read -the data and then pass the result to process(). However,</FONT> -<BR><FONT FACE="Arial,Helvetica"> application logic -may require that you read a few bytes to determine what</FONT> -<BR><FONT FACE="Arial,Helvetica"> else to read... -It's best if we push that all into the application-logic</FONT> -<BR><FONT FACE="Arial,Helvetica"> level.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> return this->process (buf, sizeof -(buf));</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If we return -1 out of handle_input() -or if the reactor sees other problems</FONT> -<BR><FONT FACE="Arial,Helvetica"> with us then handle_close() -will be called. It uses our destroy() method to</FONT> -<BR><FONT FACE="Arial,Helvetica"> shut us down cleanly and -get rid of our instance.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::handle_close (ACE_HANDLE -_handle, ACE_Reactor_Mask _mask)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_handle);</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_mask);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> this->destroy ();</FONT> -<BR><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> And, at last, we get to the -application-logic level. Out of everything</FONT> -<BR><FONT FACE="Arial,Helvetica"> we've done so far, this is -the only thing that really has anything to do</FONT> -<BR><FONT FACE="Arial,Helvetica"> with what your application -will do. In this method we will read and process</FONT> -<BR><FONT FACE="Arial,Helvetica"> the client's data. -In a real appliation, you will probably have a bit more</FONT> -<BR><FONT FACE="Arial,Helvetica"> in main() to deal with command -line options but after that point, all of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> action takes place here.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::process (char *_rdbuf, -int _rdbuf_len)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Using the buffer -provided for us, we read the data from the client. If</FONT> -<BR><FONT FACE="Arial,Helvetica"> there is a read -error (eg -- recv() returns -1) then it's a pretty good</FONT> -<BR><FONT FACE="Arial,Helvetica"> bet that the -connection is gone. Likewise, if we read zero bytes then</FONT> -<BR><FONT FACE="Arial,Helvetica"> something wrong -has happened. The reactor wouldn't have called us if</FONT> -<BR><FONT FACE="Arial,Helvetica"> there wasn't -some kind of read activity but there wouldn't be activity if</FONT> -<BR><FONT FACE="Arial,Helvetica"> there were no -bytes to read...</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> On the other hand, -if we got some data then we can display it in a debug</FONT> -<BR><FONT FACE="Arial,Helvetica"> message for everyone -to see.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> switch (this->peer ().recv (_rdbuf, -_rdbuf_len))</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> case -1:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> case 0:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), --1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> default:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG -((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf));</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P> -<HR WIDTH="100%"> - -<P>That's the last of the C++ code. On the final two pages I'll -go over the Makefile and a short perl script I wrote to "assist" the -Makefile. Please... Continue... - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page06.html">Continue This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/005/page06.html b/docs/tutorials/005/page06.html deleted file mode 100644 index 95a341cf0ea..00000000000 --- a/docs/tutorials/005/page06.html +++ /dev/null @@ -1,195 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Before we go, I wanted you to see the <A HREF="Makefile">Makefile</A>. - -<P> -<HR WIDTH="100%"> -<BR> -<UL><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> -<BR><FONT FACE="Arial,Helvetica"># -$Id$</FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> - -<P><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> -<BR><FONT FACE="Arial,Helvetica"># -Local macros</FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> - -<P><FONT FACE="Arial,Helvetica"># You can generally find a Makefile in -the ACE examples, tests or the library</FONT> -<BR><FONT FACE="Arial,Helvetica"># itself that will satisfy our application -needs. This one was taken from</FONT> -<BR><FONT FACE="Arial,Helvetica"># one of the examples.</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Define the name of the binary we want to create. There has to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# a CPP file $(BIN).cpp but it doesn't necessarily have to have your</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# main() in it. Most of the time, though, it will.</FONT> -<BR><FONT FACE="Arial,Helvetica">BIN = server</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Few applications will have a single source file. We use the FILES</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# macro to build up a list of additional files to compile. Notice</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# that we leave off the extension just as with BIN</FONT> -<BR><FONT FACE="Arial,Helvetica">FILES =</FONT> -<BR><FONT FACE="Arial,Helvetica">FILES += client_handler</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# The BUILD macro is used by the ACE makefiles. Basically, it tells</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# the system what to build. I don't really know what VBIN is other</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# than it is constructed from the value of BIN. Just go with it...</FONT> -<BR><FONT FACE="Arial,Helvetica">BUILD = $(VBIN)</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Here we use some GNU make extensions to build the SRC macro. Basically,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# we're just adding .cpp to the value of BIN and for each entry of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# FILES macro.</FONT> -<BR><FONT FACE="Arial,Helvetica">SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix -.cpp,$(FILES))</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# This is used by my Indent target below. It's not a part of standard</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# ACE and you don't need it yourself.</FONT> -<BR><FONT FACE="Arial,Helvetica">HDR = *.h</FONT> - -<P><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> -<BR><FONT FACE="Arial,Helvetica"># -Include macros and targets</FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# This is where the real power lies! These included makefile components</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# are similar to the C++ templates in ACE. That is, they do a tremendous</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# amount of work for you and all you have to do is include them.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# As a matter of fact, in our project, I created a single file named</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# "app.mk" that includes all of these. Our project makefiles then -just</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# need to include app.mk to get everything they need.</FONT> - -<P><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/macros.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/rules.common.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/rules.lib.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU</FONT> -<BR><FONT FACE="Arial,Helvetica">include $(ACE_ROOT)/include/makeinclude/rules.local.GNU</FONT> - -<P><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> -<BR><FONT FACE="Arial,Helvetica"># -Local targets</FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Sometimes I like to reformat my code to make it more readable. -This is</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# more useful for the comments than anything else. Unfortunately, -the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# "indent" program doesn't quite grok C++ so I have to post-process it's</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# output just a bit.</FONT> -<BR><FONT FACE="Arial,Helvetica">Indent : #</FONT> -<BR><FONT FACE="Arial,Helvetica"> -for i in $(SRC) $(HDR) ; do \</FONT> -<BR><FONT FACE="Arial,Helvetica"> -indent -npsl -l80 -fca -fc1 -cli0 -cdb < $$i | \</FONT> -<BR><FONT FACE="Arial,Helvetica"> -sed -e 's/: :/::/g' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/^.*\(public:\)/\1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/^.*\(protected:\)/\1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/^.*\(private:\)/\1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/:\(public\)/ : \1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/:\(protected\)/ : \1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> --e 's/:\(private\)/ : \1/' \</FONT> -<BR><FONT FACE="Arial,Helvetica"> -> $$i~ ;\</FONT> -<BR><FONT FACE="Arial,Helvetica"> -mv $$i~ $$i ;\</FONT> -<BR><FONT FACE="Arial,Helvetica"> -done</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# One of the targets in the ACE makefiles is "depend". It will invoke</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# your compiler in a way that will generate a list of dependencies for</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# you. This is a great thing! Unfortunately, it puts all of -that mess</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# directly into the Makefile. I prefer my Makefile to stay clean -and</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# uncluttered. The perl script referenced here pulls the dependency</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# stuff back out of the Makefile and into a file ".depend" which we then</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# include just like the makefile components above.</FONT> -<BR><FONT FACE="Arial,Helvetica">Depend : depend</FONT> -<BR><FONT FACE="Arial,Helvetica"> -perl fix.Makefile</FONT> -<BR><FONT FACE="Arial,Helvetica"> </FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> -<BR><FONT FACE="Arial,Helvetica"># -Dependencies</FONT> -<BR><FONT FACE="Arial,Helvetica">#----------------------------------------------------------------------------</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Don't put anything below here. Between the "depend" target and -fix.Makefile</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# it's guaranteed to be lost!</FONT> - -<P><FONT FACE="Arial,Helvetica"> -# This is inserted by the fix.Makefile script</FONT> -<BR><FONT FACE="Arial,Helvetica">include .depend</FONT></UL> - -<HR WIDTH="100%"> - -<P>Remember, make wants to see tabs leading all of the directives. -If you do a cut/paste job you'll need to convert all leading spaces to -tabs or make will be very unhappy with you. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page07.html">Continue This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/005/page07.html b/docs/tutorials/005/page07.html deleted file mode 100644 index 069f94be956..00000000000 --- a/docs/tutorials/005/page07.html +++ /dev/null @@ -1,123 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>And last (and probably least) is the <A HREF="fix.Makefile">perl script</A> -that pulls the dependency stuff out of Makefile and into .depend. - -<P> -<HR WIDTH="100%"> -<BR> <FONT FACE="Arial,Helvetica">#!/usr/bin/perl</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Open the Makefile that has been mangled by 'make depend'</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# and suck it into a perl array.</FONT> -<BR><FONT FACE="Arial,Helvetica">open(IF,"<Makefile") || die;</FONT> -<BR><FONT FACE="Arial,Helvetica">@makefile = <IF>;</FONT> -<BR><FONT FACE="Arial,Helvetica">close(IF);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Now open our .depend file and a temporary Makefile.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# We'll split the original Makefile between these two.</FONT> -<BR><FONT FACE="Arial,Helvetica">open(DF,">.depend") || die;</FONT> -<BR><FONT FACE="Arial,Helvetica">open(MF,">Makefile.tmp") || die;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# For each line we read out of the original file...</FONT> -<BR><FONT FACE="Arial,Helvetica">foreach (@makefile) {</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# If we're into the dependency section, write the line</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# into the .depend file.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -#</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( $depend ) {</FONT> -<BR><FONT FACE="Arial,Helvetica"> -print DF $_;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT> -<BR><FONT FACE="Arial,Helvetica"> -else {</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# If we haven't gotten to the dependency section yet</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# then see if the current line is the separator that</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# "make depend" causes to be inserted.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -#</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( m/^\Q# DO NOT DELETE THIS LINE -- g++dep uses it.\E/ ) {</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# If so, change our "mode" and skip this line.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -++$depend;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -next;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Also skip the "include .depend" that we insert. If we</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# don't do this, it is possible to have a bunch of these</FONT> -<BR><FONT FACE="Arial,Helvetica"> -# inserted into the output when we read an unmangled Makefile</FONT> -<BR><FONT FACE="Arial,Helvetica"> -next if( m/^include .depend/ );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -# Print the non-dependency info to the temporary Makefile</FONT> -<BR><FONT FACE="Arial,Helvetica"> -print MF $_;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"># Tell our new Makefile to include the -dependency file</FONT> -<BR><FONT FACE="Arial,Helvetica">print MF "include .depend\n";</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"># Close the two output files...</FONT> -<BR><FONT FACE="Arial,Helvetica">close(DF);</FONT> -<BR><FONT FACE="Arial,Helvetica">close(MF);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"># Unlink (remove) the original Makefile -and rename our</FONT> -<BR><FONT FACE="Arial,Helvetica"># temporary file. There's obviously -room for error checking</FONT> -<BR><FONT FACE="Arial,Helvetica"># here but we've got the Makefile checked -into some revision</FONT> -<BR><FONT FACE="Arial,Helvetica"># control system anyway. Don't we?</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">unlink("Makefile");</FONT> -<BR><FONT FACE="Arial,Helvetica">rename("Makefile.tmp","Makefile");</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">exit(0);</FONT> - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page08.html">Continue This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/005/page08.html b/docs/tutorials/005/page08.html deleted file mode 100644 index 6cc18602049..00000000000 --- a/docs/tutorials/005/page08.html +++ /dev/null @@ -1,53 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>That's it for Tutorial 5. In this tutorial we've built a single-threaded -reactor-based server. We've done a couple of things that aren't exactly -necessary for such an implementation but I plan to build on that as -we explore two other concurrency strategies: thread per connection -and thread pool. - -<P>For reference, here's the file list again: -<UL> -<LI> -<A HREF="Makefile">Makefile</A></LI> - -<LI> -<A HREF="client_acceptor.h">client_acceptor.h</A></LI> - -<LI> -<A HREF="client_handler.cpp">client_handler.cpp</A></LI> - -<LI> -<A HREF="client_handler.h">client_handler.h</A></LI> - -<LI> -<A HREF="server.cpp">server.cpp</A></LI> - -<LI> -<A HREF="fix.Makefile">fix.Makefile</A></LI> -</UL> - - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/005/server.brk b/docs/tutorials/005/server.brk deleted file mode 100644 index ba3d878a1da..00000000000 --- a/docs/tutorials/005/server.brk +++ /dev/null @@ -1,154 +0,0 @@ - -#include "ace/Acceptor.h" -#include "ace/SOCK_Acceptor.h" -#include "ace/Reactor.h" -#include "ace/Thread.h" - - -ACE_Reactor * g_reactor; - -static sig_atomic_t finished = 0; - -class Logging_Handler; - -extern "C" void handler (int) { finished = 1; } - - - -class Reactor_Derived : public ACE_Reactor -{ - -public : - Reactor_Derived() : () - { - counter = 0; - } - - virtual ~Reactor_Derived() - { - cout << "*****Calling the reactor destructor*****" << endl; - } - -private : - friend class Logging_Handler; - - // counter is used to keep track of the number of service handlers - // registered with this reactor (Surely theres a better way ;-) - int counter; -}; - -class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -{ - -public: - - Logging_Handler (void) { }; - - virtual void destroy (void) - { - if (this->thread_reactorP->remove_handler(this, - ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL) == -1 - ) - ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t remove service from reactor\n"), -1); - - // Decrement the handler tracking variable in the reactor to - // indicate this service handler has terminated - --thread_reactorP->counter; - - this->peer ().close (); - delete this; - } - - static void *run_thread(Logging_Handler *this_) - { - Reactor_Derived thread_reactor; - - this_->thread_reactorP = &thread_reactor; - - // Increment our handler counter to account for this service handler - ++thread_reactor.counter; - - if (thread_reactor.register_handler(this_, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR,"can'(%P|%t) t register with reactor\n"), -1); - - while( thread_reactor.counter > 0 ) - { - // If thread_reactor.counter = 0 then we have no more service - // handlers connected to the reactor. We set a timeout value - // of 1 second so that the handle_events loop break out every - // second to check on the count ( because of it blocking - // even when there are no connections we need to do this) - thread_reactor.handle_events(ACE_Time_Value(1,0)); - } - } - - virtual int open (void *) - { - ACE_Thread::spawn(&Logging_Handler::run_thread,this); - 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; - } - - -private: - Reactor_Derived *thread_reactorP; -}; - - -typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor; - - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main (int argc, char *argv[]) -{ - g_reactor = new ACE_Reactor; - - // Acceptor factory. - Logging_Acceptor peer_acceptor; - - if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - - 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 ) - g_reactor->handle_events (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n")); - - return 0; -} diff --git a/docs/tutorials/005/server.cpp b/docs/tutorials/005/server.cpp deleted file mode 100644 index ee46a9d2b57..00000000000 --- a/docs/tutorials/005/server.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// $Id$ - -/* - We try to keep main() very simple. One of the ways we do that is to push - much of the complicated stuff into worker objects. In this case, we only - need to include the acceptor header in our main source file. We let it - worry about the "real work". - */ - -#include "client_acceptor.h" - -/* - As before, we create a simple signal handler that will set our finished - flag. There are, of course, more elegant ways to handle program shutdown - requests but that isn't really our focus right now, so we'll just do the - easiest thing. - */ - -static sig_atomic_t finished = 0; -extern "C" void handler (int) -{ - finished = 1; -} - -/* - A server has to listen for clients at a known TCP/IP port. The default ACE - port is 10002 (at least on my system) and that's good enough for what we - want to do here. Obviously, a more robust application would take a command - line parameter or read from a configuration file or do some other clever - thing. Just like the signal handler above, though, that's what we want to - focus on, so we're taking the easy way out. - */ - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -/* - Finally, we get to main. Some C++ compilers will complain loudly if your - function signature doesn't match the prototype. Even though we're not - going to use the parameters, we still have to specify them. - */ - -int main (int argc, char *argv[]) -{ -/* - In our earlier servers, we used a global pointer to get to the reactor. I've - never really liked that idea, so I've moved it into main() this time. When - we get to the Client_Handler object you'll see how we manage to get a - pointer back to this reactor. - */ - ACE_Reactor reactor; - - /* - The acceptor will take care of letting clients connect to us. It will - also arrange for a Client_Handler to be created for each new client. - Since we're only going to listen at one TCP/IP port, we only need one - acceptor. If we wanted, though, we could create several of these and - listen at several ports. (That's what we would do if we wanted to rewrite - inetd for instance.) - */ - Client_Acceptor peer_acceptor; - - /* - Create an ACE_INET_Addr that represents our endpoint of a connection. We - then open our acceptor object with that Addr. Doing so tells the acceptor - where to listen for connections. Servers generally listen at "well known" - addresses. If not, there must be some mechanism by which the client is - informed of the server's address. - - Note how ACE_ERROR_RETURN is used if we fail to open the acceptor. This - technique is used over and over again in our tutorials. - */ - if (peer_acceptor.open (ACE_INET_Addr (PORT), &reactor) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - - /* - Here, we know that the open was successful. If it had failed, we would - have exited above. A nice side-effect of the open() is that we're already - registered with the reactor we provided it. - */ - - /* - Install our signal handler. You can actually register signal handlers - with the reactor. You might do that when the signal handler is - responsible for performing "real" work. Our simple flag-setter doesn't - justify deriving from ACE_Event_Handler and providing a callback function - though. - */ - ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - /* - Like ACE_ERROR_RETURN, the ACE_DEBUG macro gets used quite a bit. It's a - handy way to generate uniform debug output from your program. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server daemon\n")); - - /* - This will loop "forever" invoking the handle_events() method of our - reactor. handle_events() watches for activity on any registered handlers - and invokes their appropriate callbacks when necessary. Callback-driven - programming is a big thing in ACE, you should get used to it. If the - signal handler catches something, the finished flag will be set and we'll - exit. Conveniently enough, handle_events() is also interrupted by signals - and will exit back to the while() loop. (If you want your event loop to - not be interrupted by signals, checkout the <i>restart</i> flag on the - open() method of ACE_Reactor if you're interested.) - */ - while (!finished) - reactor.handle_events (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server daemon\n")); - - return 0; -} - -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/docs/tutorials/006/Makefile b/docs/tutorials/006/Makefile deleted file mode 100644 index f3523c14d00..00000000000 --- a/docs/tutorials/006/Makefile +++ /dev/null @@ -1,98 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -# You can generally find a Makefile in the ACE examples, tests or the library -# itself that will satisfy our application needs. This one was taken from -# one of the examples. - - # Define the name of the binary we want to create. There has to be - # a CPP file $(BIN).cpp but it doesn't necessarily have to have your - # main() in it. Most of the time, though, it will. -BIN = server - - # Few applications will have a single source file. We use the FILES - # macro to build up a list of additional files to compile. Notice - # that we leave off the extension just as with BIN -FILES = -FILES += client_handler - - # The BUILD macro is used by the ACE makefiles. Basically, it tells - # the system what to build. I don't really know what VBIN is other - # than it is constructed from the value of BIN. Just go with it... -BUILD = $(VBIN) - - # Here we use some GNU make extensions to build the SRC macro. Basically, - # we're just adding .cpp to the value of BIN and for each entry of the - # FILES macro. -SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES)) - - # This is used by my Indent target below. It's not a part of standard - # ACE and you don't need it yourself. -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - - # This is where the real power lies! These included makefile components - # are similar to the C++ templates in ACE. That is, they do a tremendous - # amount of work for you and all you have to do is include them. - # As a matter of fact, in our project, I created a single file named - # "app.mk" that includes all of these. Our project makefiles then just - # need to include app.mk to get everything they need. - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - - # Sometimes I like to reformat my code to make it more readable. This is - # more useful for the comments than anything else. Unfortunately, the - # "indent" program doesn't quite grok C++ so I have to post-process it's - # output just a bit. -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - - # One of the targets in the ACE makefiles is "depend". It will invoke - # your compiler in a way that will generate a list of dependencies for - # you. This is a great thing! Unfortunately, it puts all of that mess - # directly into the Makefile. I prefer my Makefile to stay clean and - # uncluttered. The perl script referenced here pulls the dependency - # stuff back out of the Makefile and into a file ".depend" which we then - # include just like the makefile components above. -Depend : depend - perl fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - - # Don't put anything below here. Between the "depend" target and fix.Makefile - # it's guaranteed to be lost! - - # This is inserted by the fix.Makefile script -include .depend diff --git a/docs/tutorials/006/client_acceptor.h b/docs/tutorials/006/client_acceptor.h deleted file mode 100644 index 2318b6adacd..00000000000 --- a/docs/tutorials/006/client_acceptor.h +++ /dev/null @@ -1,85 +0,0 @@ - -// $Id$ - -#ifndef CLIENT_ACCEPTOR_H -#define CLIENT_ACCEPTOR_H - -/* - The ACE_Acceptor<> template lives in the ace/Acceptor.h header file. You'll - find a very consitent naming convention between the ACE objects and the - headers where they can be found. In general, the ACE object ACE_Foobar will - - - be found in ace/Foobar.h. - */ - -#include "ace/Acceptor.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -/* - Since we want to work with sockets, we'll need a SOCK_Acceptor to allow the - clients to connect to us. - */ -#include "ace/SOCK_Acceptor.h" - -/* - The Client_Handler object we develop will be used to handle clients once - they're connected. The ACE_Acceptor<> template's first parameter requires - such an object. In some cases, you can get by with just a forward - declaration on the class, in others you have to have the whole thing. - */ -#include "client_handler.h" - -/* - Parameterize the ACE_Acceptor<> such that it will listen for socket - connection attempts and create Client_Handler objects when they happen. In - Tutorial 001, we wrote the basic acceptor logic on our own before we - realized that ACE_Acceptor<> was available. You'll get spoiled using the - ACE templates because they take away a lot of the tedious details! - */ -typedef ACE_Acceptor < Client_Handler, ACE_SOCK_ACCEPTOR > Client_Acceptor_Base; - -/* - Here, we use the parameterized ACE_Acceptor<> as a baseclass for our customized - Client_Acceptor object. I've done this so that we can provide it with our choice - of concurrency strategies when the object is created. Each Client_Handler it - creates will use this information to determine how to act. If we were going - to create a system that was always thread-per-connection, we would not have - bothered to extend Client_Acceptor. - */ -class Client_Acceptor : public Client_Acceptor_Base -{ -public: - /* - This is always a good idea. If nothing else, it makes your code more - orthogonal no matter what baseclasses your objects have. - */ - typedef Client_Acceptor_Base inherited; - - /* - Construct the object with the concurrency strategy. Since this tutorial - is focused on thread-per-connection, we make that the default. We could - have chosen to omitt the default and populate it in main() instead. - */ - Client_Acceptor( int _thread_per_connection = 1 ) - : thread_per_connection_(_thread_per_connection) - { - } - - /* - Return the value of our strategy flag. This is used by the Client_Handler - to decide how to act. If 'true' then the handler will behave in a - thread-per-connection manner. - */ - int thread_per_connection(void) - { return this->thread_per_connection_; } - -protected: - int thread_per_connection_; - -}; - -#endif // CLIENT_ACCEPTOR_H diff --git a/docs/tutorials/006/client_handler.cpp b/docs/tutorials/006/client_handler.cpp deleted file mode 100644 index 16fd098f12c..00000000000 --- a/docs/tutorials/006/client_handler.cpp +++ /dev/null @@ -1,313 +0,0 @@ - -// $Id$ - -/* - In client_handler.h I alluded to the fact that we'll mess around with a - Client_Acceptor pointer. To do so, we need the Client_Acceptor object - declaration. - - We know that including client_handler.h is redundant because - client_acceptor.h includes it. Still, the sentry prevents double-inclusion - from causing problems and it's sometimes good to be explicit about what - we're using. - - On the other hand, we don't directly include any ACE header files here. - */ -#include "client_acceptor.h" -#include "client_handler.h" - -/* - Our constructor doesn't do anything. That's generally a good idea. Unless - you want to start throwing exceptions, there isn't a really good way to - indicate that a constructor has failed. If I had my way, I'd have a boolean - return code from it that would cause new to return 0 if I failed. Oh - well... - */ -Client_Handler::Client_Handler (void) -{ -} - -/* - Our destructor doesn't do anything either. That is also by design. - Remember, we really want folks to use destroy() to get rid of us. If that's - so, then there's nothing left to do when the destructor gets invoked. - */ -Client_Handler::~Client_Handler (void) -{ -} - -/* - The much talked about destroy() method! The reason I keep going on about - this is because it's just a Bad Idea (TM) to do real work inside of a - destructor. Although this method is void, it really should return - int so that it can tell the caller there was a problem. Even as - void you could at least throw an exception which you would never want - to do in a destructor. - */ -void Client_Handler::destroy (void) -{ - /* - We probably got here because of an error on the stream, so the peer - connection is probably already closed. Still... there are other ways to - get here and closing a closed peer doesn't hurt. - */ - this->peer ().close (); - - /* - Tell the reactor to forget all about us. Notice that we use the same args - here that we use in the open() method to register ourselves. In addition, - we use the DONT_CALL flag to prevent handle_close() being called. Since we - likely got here due to handle_close(), that could cause a bit of nasty - recursion! - */ - this->reactor ()->remove_handler (this, - ACE_Event_Handler:: READ_MASK | ACE_Event_Handler::DONT_CALL); - - /* - This is how we're able to tell folks not to use delete. By - deleting our own instance, we take care of memory leaks after ensuring - that the object is shut down correctly. - */ - delete this; -} - -/* - As mentioned before, the open() method is called by the Client_Acceptor when - a new client connection has been accepted. The Client_Acceptor instance - pointer is cast to a void* and given to us here. We'll use that to avoid - some global data... - */ -int Client_Handler::open (void *_acceptor) -{ - /* - We need this to store the address of the client that we are now connected - to. We'll use it later to display a debug message. - */ - ACE_INET_Addr addr; - - /* - Our ACE_Svc_Handler baseclass gives us the peer() method as a way to - access our underlying ACE_SOCK_Stream. On that object, we can invoke the - get_remote_addr() method to get get an ACE_INET_Addr having our client's - address information. As with most ACE methods, we'll get back (and return) - a -1 if there was any kind of error. Once we have the ACE_INET_Addr, we - can query it to find out the clien's host name, TCP/IP address, TCP/IP - port value and so forth. One word of warning: the get_host_name() - method of ACE_INET_Addr may return you an empty string if your name server - can't resolve it. On the other hand, get_host_addr() will always give you - the dotted-decimal string representing the TCP/IP address. - */ - if (this->peer ().get_remote_addr (addr) == -1) - { - return -1; - } - - /* - Convert the void* to a Client_Acceptor*. You should probably use those - fancy new C++ cast operators but I can never remember how/when to do so. - Since you can cast just about anything around a void* without compiler - warnings be very sure of what you're doing when you do this kind of thing. - That's where the new-style cast operators can save you. - */ - Client_Acceptor *acceptor = (Client_Acceptor *) _acceptor; - - /* - Our Client_Acceptor is constructed with a concurrency strategy. Here, we - go back to it to find out what that strategy was. If thread-per-connection - was selected then we simply activate a thread for ourselves and exit. Our - svc() method will then begin executing in that thread. - - If we are told to use the single-threaded strategy, there is no difference - between this and the Tutorial 5 implementation. - */ - if( acceptor->thread_per_connection() ) - { - return this->activate(); - } - - /* - Our reactor reference will be set when we register ourselves but I decided - to go ahead and set it here. No good reason really... - */ - this->reactor (acceptor->reactor ()); - - /* - If we managed to get the client's address then we're connected to a real - and valid client. I suppose that in some cases, the client may connect - and disconnect so quickly that it is invalid by the time we get here. In - any case, the test above should always be done to ensure that the - connection is worth keeping. - - Now, regiser ourselves with a reactor and tell that reactor that we want - to be notified when there is something to read. Remember, we took our - reactor value from the acceptor which created us in the first place. - Since we're exploring a single-threaded implementation, this is the - correct thing to do. - */ - if (this->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, we use the ACE_INET_Addr object to print a message with the name of - the client we're connected to. Again, it is possible that you'll get an - empty string for the host name if your DNS isn't configured correctly or - if there is some other reason that a TCP/IP addreess cannot be converted - into a host name. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name ())); - - /* - Always return zero on success. - */ - return 0; -} - -/* - As mentioned in the header, the typical way to close an object in a threaded - context is to invoke it's close() method. Since we already have a handle_close() - method built to cleanup after us, we'll just forward the request on to that - object. - */ -int Client_Handler::close(u_long flags) -{ - /* - Down in the depths of our baseclass, this will eventually cause us - to be destroyed. Since all of the destructors are virtual, everything - gets cleaned up nicely. - */ - this->handle_close(ACE_INVALID_HANDLE,0); - - /* - Don't forward the close() to the baseclass! handle_close() above has - already taken care of delete'ing. Forwarding close() would cause that - to happen again and things would get really ugly at that point! - */ - return 0; -} - -/* - In the open() method, we registered with the reactor and requested to be - notified when there is data to be read. When the reactor sees that activity - it will invoke this handle_input() method on us. As I mentioned, the _handle - parameter isn't useful to us but it narrows the list of methods the reactor - has to worry about and the list of possible virtual functions we would have - to override. - */ -int Client_Handler::handle_input (ACE_HANDLE _handle) -{ - /* - Some compilers don't like it when you fail to use a parameter. This macro - will keep 'em quiet for you. - */ - ACE_UNUSED_ARG (_handle); - - /* - Now, we create and initialize a buffer for receiving the data. Since this - is just a simple test app, we'll use a small buffer size. - */ - char buf[128]; - ACE_OS::memset (buf, 0, sizeof (buf)); - - /* - Invoke the process() method with a pointer to our data area. We'll let - that method worry about interfacing with the data. You might choose to go - ahead and read the data and then pass the result to process(). However, - application logic may require that you read a few bytes to determine what - else to read... It's best if we push that all into the application-logic - level. - */ - return this->process (buf, sizeof (buf)); -} - -/* - If we return -1 out of handle_input() or if the reactor sees other problems - with us then handle_close() will be called. It uses our destroy() method to - shut us down cleanly and get rid of our instance. - */ -int Client_Handler::handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask) -{ - ACE_UNUSED_ARG (_handle); - ACE_UNUSED_ARG (_mask); - - this->destroy (); - return 0; -} - -/* - The ACE_Svc_Handler<> is ultimately derived from ACE_Task<>. If you want to - create a multi-threaded application, these are your tools! Simply override - the svc() method in your derivative and arrange for your activate() method - to be called. The svc() method then executes in the new thread. - */ -int Client_Handler::svc(void) -{ - /* - Like handle_input(), we create a buffer for loading the data. Doing so - in handle_input() doesn't help any but there is a small performance increase - by doing this here: the buffer is created once when the thread is created - instead of for each invocation of process(). - */ - char buf[128]; - - // Forever... - while( 1 ) - { - // Clean the buffer... - ACE_OS::memset (buf, 0, sizeof (buf)); - - /* - Invoke the proces() method to read and process the data. This is - exactly the way it is used by handle_input(). That's the reason I - created process() in the first place: so that it can be used in either - concurrency strategy. Since process() has all of our application-level - logic, it's nice that it doesn't have to change when we decide to go - multi-threaded. - - Notice that since the recv() method call in process() blocks until - there is data ready, this thread doesn't consume any CPU time until - there is actually data sent from the client. - */ - if( this->process(buf,sizeof(buf)) == -1 ) - { - return(-1); - } - } - - return(0); -} - -/* - And, at last, we get to the application-logic level. Out of everything - we've done so far, this is the only thing that really has anything to do - with what your application will do. In this method we will read and process - the client's data. In a real appliation, you will probably have a bit more - in main() to deal with command line options but after that point, all of the - action takes place here. - */ -int Client_Handler::process (char *_rdbuf, int _rdbuf_len) -{ - /* - Using the buffer provided for us, we read the data from the client. If - there is a read error (eg -- recv() returns -1) then it's a pretty good - bet that the connection is gone. Likewise, if we read zero bytes then - something wrong has happened. The reactor wouldn't have called us if - there wasn't some kind of read activity but there wouldn't be activity if - there were no bytes to read... - - On the other hand, if we got some data then we can display it in a debug - message for everyone to see. - */ - switch (this->peer ().recv (_rdbuf, _rdbuf_len)) - { - case -1: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1); - case 0: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), -1); - default: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf)); - } - - return 0; -} diff --git a/docs/tutorials/006/client_handler.h b/docs/tutorials/006/client_handler.h deleted file mode 100644 index 83a4c326b94..00000000000 --- a/docs/tutorials/006/client_handler.h +++ /dev/null @@ -1,126 +0,0 @@ - -// $Id$ - -#ifndef CLIENT_HANDLER_H -#define CLIENT_HANDLER_H - -/* - Our client handler must exist somewhere in the ACE_Event_Handler object - hierarchy. This is a requirement of the ACE_Reactor because it maintains - ACE_Event_Handler pointers for each registered event handler. You could - derive our Client_Handler directly from ACE_Event_Handler but you still have - to have an ACE_SOCK_Stream for the actually connection. With a direct - derivative of ACE_Event_Handler, you'll have to contain and maintain an - ACE_SOCK_Stream instance yourself. With ACE_Svc_Handler (which is a - derivative of ACE_Event_Handler) some of those details are handled for you. - - */ - -#include "ace/Svc_Handler.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "ace/SOCK_Stream.h" - -/* - Another feature of ACE_Svc_Handler is it's ability to present the ACE_Task<> - interface as well. That's what the ACE_NULL_SYNCH parameter below is all - about. If our Client_Acceptor has chosen thread-per-connection then our - open() method will activate us into a thread. At that point, our svc() - method will execute. We still don't take advantage of the thiings - ACE_NULL_SYNCH exists for but stick around for Tutorial 7 and pay special - attention to the Thread_Pool object there for an explanation. - */ -class Client_Handler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > -{ -public: - typedef ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > inherited; - - // Constructor... - Client_Handler (void); - - /* - The destroy() method is our preferred method of destruction. We could - have overloaded the delete operator but that is neither easy nor - intuitive (at least to me). Instead, we provide a new method of - destruction and we make our destructor protected so that only ourselves, - our derivatives and our friends can delete us. It's a nice - compromise. - */ - void destroy (void); - - /* - Most ACE objects have an open() method. That's how you make them ready - to do work. ACE_Event_Handler has a virtual open() method which allows us - to create this overrride. ACE_Acceptor<> will invoke this method after - creating a new Client_Handler when a client connects. Notice that the - parameter to open() is a void*. It just so happens that the pointer - points to the acceptor which created us. You would like for the parameter - to be an ACE_Acceptor<>* but since ACE_Event_Handler is generic, that - would tie it too closely to the ACE_Acceptor<> set of objects. In our - definition of open() you'll see how we get around that. - */ - int open (void *_acceptor); - - /* - When an ACE_Task<> object falls out of the svc() method, the framework - will call the close() method. That's where we want to cleanup ourselves - if we're running in either thread-per-connection or thread-pool mode. - */ - int close(u_long flags = 0); - - /* - When there is activity on a registered handler, the handle_input() method - of the handler will be invoked. If that method returns an error code (eg - -- -1) then the reactor will invoke handle_close() to allow the object to - clean itself up. Since an event handler can be registered for more than - one type of callback, the callback mask is provided to inform - handle_close() exactly which method failed. That way, you don't have to - maintain state information between your handle_* method calls. The _handle - parameter is explained below... - */ - int handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask); - -protected: - - /* - If the Client_Acceptor which created us has chosen a thread-per-connection - strategy then our open() method will activate us into a dedicate thread. - The svc() method will then execute in that thread performing some of the - functions we used to leave up to the reactor. - */ - int svc(void); - - /* - When we register with the reactor, we're going to tell it that we want to - be notified of READ events. When the reactor sees that there is read - activity for us, our handle_input() will be invoked. The _handleg - provided is the handle (file descriptor in Unix) of the actual connection - causing the activity. Since we're derived from ACE_Svc_Handler<> and it - maintains it's own peer (ACE_SOCK_Stream) object, this is redundant for - us. However, if we had been derived directly from ACE_Event_Handler, we - may have chosen not to contain the peer. In that case, the _handleg - would be important to us for reading the client's data. - */ - int handle_input (ACE_HANDLE _handle); - - /* - This has nothing at all to do with ACE. I've added this here as a worker - function which I will call from handle_input(). As promised in Tutorial 5 - I will use this now to make it easier to switch between our two possible - concurrency strategies. - */ - int process (char *_rdbuf, int _rdbuf_len); - - /* - We don't really do anything in our destructor but we've declared it to be - protected to prevent casual deletion of this object. As I said above, I - really would prefer that everyone goes through the destroy() method to get - rid of us. - */ - ~Client_Handler (void); -}; - -#endif // CLIENT_HANDLER_H diff --git a/docs/tutorials/006/fix.Makefile b/docs/tutorials/006/fix.Makefile deleted file mode 100644 index e99c194114a..00000000000 --- a/docs/tutorials/006/fix.Makefile +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/perl - - # Open the Makefile that has been mangled by 'make depend' - # and suck it into a perl array. -open(IF,"<Makefile") || die; -@makefile = <IF>; -close(IF); - - # Now open our .depend file and a temporary Makefile. - # We'll split the original Makefile between these two. -open(DF,">.depend") || die; -open(MF,">Makefile.tmp") || die; - - # For each line we read out of the original file... -foreach (@makefile) { - - # If we're into the dependency section, write the line - # into the .depend file. - # - if( $depend ) { - print DF $_; - } - else { - # If we haven't gotten to the dependency section yet - # then see if the current line is the separator that - # "make depend" causes to be inserted. - # - if( m/^\Q# DO NOT DELETE THIS LINE -- g++dep uses it.\E/ ) { - - # If so, change our "mode" and skip this line. - ++$depend; - next; - } - - # Also skip the "include .depend" that we insert. If we - # don't do this, it is possible to have a bunch of these - # inserted into the output when we read an unmangled Makefile - next if( m/^include .depend/ ); - - # Print the non-dependency info to the temporary Makefile - print MF $_; - } -} - -# Tell our new Makefile to include the dependency file -print MF "include .depend\n"; - -# Close the two output files... -close(DF); -close(MF); - -# Unlink (remove) the original Makefile and rename our -# temporary file. There's obviously room for error checking -# here but we've got the Makefile checked into some revision -# control system anyway. Don't we? - -unlink("Makefile"); -rename("Makefile.tmp","Makefile"); - -exit(0); diff --git a/docs/tutorials/006/page01.html b/docs/tutorials/006/page01.html deleted file mode 100644 index cd20f343e91..00000000000 --- a/docs/tutorials/006/page01.html +++ /dev/null @@ -1,33 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 006</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In this tutorial, we're going to extend Tutorial 5 to create a thread-per-connection -server. This implementation will create a new thread for each client -which connects to us. The ACE_Reactor is still used but only for -accepting new connections. The Client_Handler objects won't be registered -with the reactor. Instead, they'll be responsible for monitoring -their peer() directly. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/006/page02.html b/docs/tutorials/006/page02.html deleted file mode 100644 index 29d4c457ff1..00000000000 --- a/docs/tutorials/006/page02.html +++ /dev/null @@ -1,205 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 006</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Again, we begin with <A HREF="server.cpp">server.cpp.</A> If you -look closely you will see that the only difference between this and the -Tutorial 5 implementation is a single comment. - -<P> -<HR WIDTH="100%"><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">// $Id: server.cpp,v 1.1 1998/08/30 13:38:28 -jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We try to keep main() very -simple. One of the ways we do that is to push</FONT> -<BR><FONT FACE="Arial,Helvetica"> much of the complicated stuff -into worker objects. In this case, we only</FONT> -<BR><FONT FACE="Arial,Helvetica"> need to include the acceptor -header in our main source file. We let it</FONT> -<BR><FONT FACE="Arial,Helvetica"> worry about the "real work".</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As before, we create a simple -signal handler that will set our finished</FONT> -<BR><FONT FACE="Arial,Helvetica"> flag. There are, of -course, more elegant ways to handle program shutdown</FONT> -<BR><FONT FACE="Arial,Helvetica"> requests but that isn't really -our focus right now, so we'll just do the</FONT> -<BR><FONT FACE="Arial,Helvetica"> easiest thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">static sig_atomic_t finished = 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">extern "C" void handler (int)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> finished = 1;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> A server has to listen for -clients at a known TCP/IP port. The default ACE</FONT> -<BR><FONT FACE="Arial,Helvetica"> port is 10002 (at least on -my system) and that's good enough for what we</FONT> -<BR><FONT FACE="Arial,Helvetica"> want to do here. Obviously, -a more robust application would take a command</FONT> -<BR><FONT FACE="Arial,Helvetica"> line parameter or read from -a configuration file or do some other clever</FONT> -<BR><FONT FACE="Arial,Helvetica"> thing. Just like the -signal handler above, though, that's what we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> focus on, so we're taking -the easy way out.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Finally, we get to main. -Some C++ compilers will complain loudly if your</FONT> -<BR><FONT FACE="Arial,Helvetica"> function signature doesn't -match the prototype. Even though we're not</FONT> -<BR><FONT FACE="Arial,Helvetica"> going to use the parameters, -we still have to specify them.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">int main (int argc, char *argv[])</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In our earlier servers, we -used a global pointer to get to the reactor. I've</FONT> -<BR><FONT FACE="Arial,Helvetica"> never really liked that idea, -so I've moved it into main() this time. When</FONT> -<BR><FONT FACE="Arial,Helvetica"> we get to the Client_Handler -object you'll see how we manage to get a</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer back to this reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Reactor reactor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The acceptor -will take care of letting clients connect to us. It will</FONT> -<BR><FONT FACE="Arial,Helvetica"> also arrange -for a Client_Handler to be created for each new client.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we're only -going to listen at one TCP/IP port, we only need one</FONT> -<BR><FONT FACE="Arial,Helvetica"> acceptor. -If we wanted, though, we could create several of these and</FONT> -<BR><FONT FACE="Arial,Helvetica"> listen at several -ports. (That's what we would do if we wanted to rewrite</FONT> -<BR><FONT FACE="Arial,Helvetica"> inetd for -instance.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor peer_acceptor;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Create an ACE_INET_Addr -that represents our endpoint of a connection. We</FONT> -<BR><FONT FACE="Arial,Helvetica"> then open our -acceptor object with that Addr. Doing so tells the acceptor</FONT> -<BR><FONT FACE="Arial,Helvetica"> where to listen -for connections. Servers generally listen at "well known"</FONT> -<BR><FONT FACE="Arial,Helvetica"> addresses. -If not, there must be some mechanism by which the client is</FONT> -<BR><FONT FACE="Arial,Helvetica"> informed of the -server's address.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Note how ACE_ERROR_RETURN -is used if we fail to open the acceptor. This</FONT> -<BR><FONT FACE="Arial,Helvetica"> technique is -used over and over again in our tutorials.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (peer_acceptor.open (ACE_INET_Addr -(PORT), &reactor) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN ((LM_ERROR, -"%p\n", "open"), -1);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As with Tutorial -5, we know that we're now registered with our reactor</FONT> -<BR><FONT FACE="Arial,Helvetica"> so we don't have -to mess with that step.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Install our signal -handler. You can actually register signal handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> with the reactor. -You might do that when the signal handler is</FONT> -<BR><FONT FACE="Arial,Helvetica"> responsible for -performing "real" work. Our simple flag-setter doesn't</FONT> -<BR><FONT FACE="Arial,Helvetica"> justify deriving -from ACE_Event_Handler and providing a callback function</FONT> -<BR><FONT FACE="Arial,Helvetica"> though.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Sig_Action sa ((ACE_SignalHandler) -handler, SIGINT);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Like ACE_ERROR_RETURN, -the ACE_DEBUG macro gets used quite a bit. It's a</FONT> -<BR><FONT FACE="Arial,Helvetica"> handy way to -generate uniform debug output from your program.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) -starting up server daemon\n"));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This will loop -"forever" invoking the handle_events() method of our</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor. handle_events() -watches for activity on any registered handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> and invokes their -appropriate callbacks when necessary. Callback-driven</FONT> -<BR><FONT FACE="Arial,Helvetica"> programming is -a big thing in ACE, you should get used to it. If the</FONT> -<BR><FONT FACE="Arial,Helvetica"> signal handler -catches something, the finished flag will be set and we'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> exit. Conveniently -enough, handle_events() is also interrupted by signals</FONT> -<BR><FONT FACE="Arial,Helvetica"> and will exit -back to the while() loop. (If you want your event loop to</FONT> -<BR><FONT FACE="Arial,Helvetica"> not be interrupted -by signals, checkout the <i>restart</i> flag on the</FONT> -<BR><FONT FACE="Arial,Helvetica"> open() method -of ACE_Reactor if you're interested.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> while (!finished)</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor.handle_events -();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting -down server daemon\n"));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Let's move along and see what happend to the Client_Acceptor. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page03.html">Continue This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/006/page03.html b/docs/tutorials/006/page03.html deleted file mode 100644 index b31b18aeac2..00000000000 --- a/docs/tutorials/006/page03.html +++ /dev/null @@ -1,167 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 006</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In <A HREF="client_acceptor.h">client_acceptor.h</A>, we've extended -our object just a bit. The primary reason is to allow us to select -the previous single-threaded implementation or our new thread-per-connection -implementation. Client_Acceptor itself doesn't use this information -but makes it available to the Client_Handler objects it creates. -If we wanted a single-strategy implementation, we would have made no changes -to the Tutorial 5 version of this file. - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: client_acceptor.h,v 1.1 1998/08/30 -13:38:27 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#ifndef CLIENT_ACCEPTOR_H</FONT> -<BR><FONT FACE="Arial,Helvetica">#define CLIENT_ACCEPTOR_H</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The ACE_Acceptor<> template -lives in the ace/Acceptor.h header file. You'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> find a very consitent naming -convention between the ACE objects and the</FONT> -<BR><FONT FACE="Arial,Helvetica"> headers where they can be -found. In general, the ACE object ACE_Foobar will</FONT> -<BR><FONT FACE="Arial,Helvetica"></FONT> <FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> be found in ace/Foobar.h.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "ace/Acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we want to work with -sockets, we'll need a SOCK_Acceptor to allow the</FONT> -<BR><FONT FACE="Arial,Helvetica"> clients to connect to us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "ace/SOCK_Acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The Client_Handler object -we develop will be used to handle clients once</FONT> -<BR><FONT FACE="Arial,Helvetica"> they're connected. -The ACE_Acceptor<> template's first parameter requires</FONT> -<BR><FONT FACE="Arial,Helvetica"> such an object. In -some cases, you can get by with just a forward</FONT> -<BR><FONT FACE="Arial,Helvetica"> declaration on the class, -in others you have to have the whole thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Parameterize the ACE_Acceptor<> -such that it will listen for socket</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection attempts and create -Client_Handler objects when they happen. In</FONT> -<BR><FONT FACE="Arial,Helvetica"> Tutorial 001, we wrote the -basic acceptor logic on our own before we</FONT> -<BR><FONT FACE="Arial,Helvetica"> realized that ACE_Acceptor<> -was available. You'll get spoiled using the</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE templates because they -take away a lot of the tedious details!</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">typedef ACE_Acceptor < Client_Handler, -ACE_SOCK_ACCEPTOR > Client_Acceptor_Base;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Here, we use the parameterized -ACE_Acceptor<> as a baseclass for our customized</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor object. -I've done this so that we can provide it with our choice</FONT> -<BR><FONT FACE="Arial,Helvetica"> of concurrency strategies -when the object is created. Each Client_Handler it</FONT> -<BR><FONT FACE="Arial,Helvetica"> creates will use this information -to determine how to act. If we were going</FONT> -<BR><FONT FACE="Arial,Helvetica"> to create a system that was -always thread-per-connection, we would not have</FONT> -<BR><FONT FACE="Arial,Helvetica"> bothered to extend -Client_Acceptor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Client_Acceptor : public Client_Acceptor_Base</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">public:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -This is always a good idea. If nothing else, it makes your code more</FONT> -<BR><FONT FACE="Arial,Helvetica"> -orthogonal no matter what baseclasses your objects have.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -typedef Client_Acceptor_Base inherited;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Construct the object with the concurrency strategy. Since this tutorial</FONT> -<BR><FONT FACE="Arial,Helvetica"> -is focused on thread-per-connection, we make that the default. We -could</FONT> -<BR><FONT FACE="Arial,Helvetica"> -have chosen to omitt the default and populate it in main() instead.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Client_Acceptor( int _thread_per_connection = 1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -: thread_per_connection_(_thread_per_connection)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Return the value of our strategy flag. This is used by the Client_Handler</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to decide how to act. If 'true' then the handler will behave in a</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread-per-connection manner.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int thread_per_connection(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ return this->thread_per_connection_; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int thread_per_connection_;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_ACCEPTOR_H</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Ok, so far we haven't done much to change our concurrency strategy. -Let's move on to the Client_Handler and see if it has changed any. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/006/page04.html b/docs/tutorials/006/page04.html deleted file mode 100644 index 7cdb48180af..00000000000 --- a/docs/tutorials/006/page04.html +++ /dev/null @@ -1,223 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 006</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P><A HREF="client_handler.h">client_handler.h</A> -shows a few more changes than the previous sources. The important -change is the addition of a svc() method where our connection thread will -exist. - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: client_handler.h,v 1.1 1998/08/30 -23:47:13 schmidt Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#ifndef CLIENT_HANDLER_H</FONT> -<BR><FONT FACE="Arial,Helvetica">#define CLIENT_HANDLER_H</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our client handler must exist -somewhere in the ACE_Event_Handler object</FONT> -<BR><FONT FACE="Arial,Helvetica"> hierarchy. This is -a requirement of the ACE_Reactor because it maintains</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Event_Handler pointers -for each registered event handler. You could</FONT> -<BR><FONT FACE="Arial,Helvetica"> derive our Client_Handler -directly from ACE_Event_Handler but you still have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to have an ACE_SOCK_Stream -for the actually connection. With a direct</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler, -you'll have to contain and maintain an</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_SOCK_Stream instance -yourself. With ACE_Svc_Handler (which is a</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler) -some of those details are handled for you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> </FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "ace/Svc_Handler.h"</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "ace/SOCK_Stream.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Another feature of ACE_Svc_Handler -is it's ability to present the ACE_Task<></FONT> -<BR><FONT FACE="Arial,Helvetica"> interface as well. -That's what the ACE_NULL_SYNCH parameter below is all</FONT> -<BR><FONT FACE="Arial,Helvetica"> about. If our Client_Acceptor -has chosen thread-per-connection then our</FONT> -<BR><FONT FACE="Arial,Helvetica"> open() method will activate -us into a thread. At that point, our svc()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method will execute. -We still don't take advantage of the thiings</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_NULL_SYNCH exists for -but stick around for Tutorial 7 and pay special</FONT> -<BR><FONT FACE="Arial,Helvetica"> attention to the Thread_Pool -object there for an explanation.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Client_Handler : public ACE_Svc_Handler -< ACE_SOCK_STREAM, ACE_NULL_SYNCH ></FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">public:</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> // Constructor...</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The destroy() -method is our preferred method of destruction. We could</FONT> -<BR><FONT FACE="Arial,Helvetica"> have overloaded -the delete operator but that is neither easy nor</FONT> -<BR><FONT FACE="Arial,Helvetica"> intuitive (at -least to me). Instead, we provide a new method of</FONT> -<BR><FONT FACE="Arial,Helvetica"> destruction and -we make our destructor protected so that only ourselves,</FONT> -<BR><FONT FACE="Arial,Helvetica"> our derivatives -and our friends can delete us. It's a nice</FONT> -<BR><FONT FACE="Arial,Helvetica"> compromise.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> void destroy (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Most ACE objects -have an open() method. That's how you make them ready</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do work. -ACE_Event_Handler has a virtual open() method which allows us</FONT> -<BR><FONT FACE="Arial,Helvetica"> to create this -overrride. ACE_Acceptor<> will invoke this method after</FONT> -<BR><FONT FACE="Arial,Helvetica"> creating a new -Client_Handler when a client connects. Notice that the</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter to -open() is a void*. It just so happens that the pointer</FONT> -<BR><FONT FACE="Arial,Helvetica"> points to the -acceptor which created us. You would like for the parameter</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be an ACE_Acceptor<>* -but since ACE_Event_Handler is generic, that</FONT> -<BR><FONT FACE="Arial,Helvetica"> would tie it -too closely to the ACE_Acceptor<> set of objects. In our</FONT> -<BR><FONT FACE="Arial,Helvetica"> definition of -open() you'll see how we get around that.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int open (void *_acceptor);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When an ACE_Task<> -object falls out of the svc() method, the framework</FONT> -<BR><FONT FACE="Arial,Helvetica"> will call the -close() method. That's where we want to cleanup ourselves</FONT> -<BR><FONT FACE="Arial,Helvetica"> if we're running -in either thread-per-connection or thread-pool mode.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int close(u_long flags = 0);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When there is -activity on a registered handler, the handle_input() method</FONT> -<BR><FONT FACE="Arial,Helvetica"> of the handler -will be invoked. If that method returns an error code (eg</FONT> -<BR><FONT FACE="Arial,Helvetica"> -- -1) then the -reactor will invoke handle_close() to allow the object to</FONT> -<BR><FONT FACE="Arial,Helvetica"> clean itself -up. Since an event handler can be registered for more than</FONT> -<BR><FONT FACE="Arial,Helvetica"> one type of callback, -the callback mask is provided to inform</FONT> -<BR><FONT FACE="Arial,Helvetica"> handle_close() -exactly which method failed. That way, you don't have to</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintain state -information between your handle_* method calls. The _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter is -explained below...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int handle_close (ACE_HANDLE _handle, -ACE_Reactor_Mask _mask);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If the Client_Acceptor -which created us has chosen a thread-per-connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> strategy then -our open() method will activate us into a dedicate thread.</FONT> -<BR><FONT FACE="Arial,Helvetica"> The svc() method -will then execute in that thread performing some of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> functions we -used to leave up to the reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int svc(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When we register -with the reactor, we're going to tell it that we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> be notified of -READ events. When the reactor sees that there is read</FONT> -<BR><FONT FACE="Arial,Helvetica"> activity for -us, our handle_input() will be invoked. The _handleg</FONT> -<BR><FONT FACE="Arial,Helvetica"> provided is the -handle (file descriptor in Unix) of the actual connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> causing the activity. -Since we're derived from ACE_Svc_Handler<> and it</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintains it's -own peer (ACE_SOCK_Stream) object, this is redundant for</FONT> -<BR><FONT FACE="Arial,Helvetica"> us. However, -if we had been derived directly from ACE_Event_Handler, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> may have chosen -not to contain the peer. In that case, the _handleg</FONT> -<BR><FONT FACE="Arial,Helvetica"> would be important -to us for reading the client's data.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int handle_input (ACE_HANDLE _handle);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This has nothing -at all to do with ACE. I've added this here as a worker</FONT> -<BR><FONT FACE="Arial,Helvetica"> function which -I will call from handle_input(). As promised in Tutorial 5</FONT> -<BR><FONT FACE="Arial,Helvetica"> I will use this -now to make it easier to switch between our two possible</FONT> -<BR><FONT FACE="Arial,Helvetica"> concurrency strategies.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int process (char *_rdbuf, int -_rdbuf_len);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We don't really -do anything in our destructor but we've declared it to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> protected to -prevent casual deletion of this object. As I said above, I</FONT> -<BR><FONT FACE="Arial,Helvetica"> really would -prefer that everyone goes through the destroy() method to get</FONT> -<BR><FONT FACE="Arial,Helvetica"> rid of us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ~Client_Handler (void);</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_HANDLER_H</FONT> - -<P> -<HR WIDTH="100%"> - -<P>So... we've added a svc() method and alluded to changes in open(). -Let's move on to the object definition and see what all the fuss is about. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/006/page05.html b/docs/tutorials/006/page05.html deleted file mode 100644 index 5f8bedf16d9..00000000000 --- a/docs/tutorials/006/page05.html +++ /dev/null @@ -1,516 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 006</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P><A HREF="client_handler.cpp">client_handler.cpp</A> exposes all the -things I've been hinting at. Pay special attention to the decision -made in open() as well as the bit of cleverness in svc(). - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: client_handler.cpp,v 1.1 1998/08/30 -23:47:13 schmidt Exp $</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In client_handler.h I alluded -to the fact that we'll mess around with a</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor pointer. -To do so, we need the Client_Acceptor object</FONT> -<BR><FONT FACE="Arial,Helvetica"> declaration.</FONT> - -<P><FONT FACE="Arial,Helvetica"> We know that including client_handler.h -is redundant because</FONT> -<BR><FONT FACE="Arial,Helvetica"> client_acceptor.h includes -it. Still, the sentry prevents double-inclusion</FONT> -<BR><FONT FACE="Arial,Helvetica"> from causing problems and -it's sometimes good to be explicit about what</FONT> -<BR><FONT FACE="Arial,Helvetica"> we're using.</FONT> - -<P><FONT FACE="Arial,Helvetica"> On the other hand, we don't -directly include any ACE header files here.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our constructor doesn't do -anything. That's generally a good idea. Unless</FONT> -<BR><FONT FACE="Arial,Helvetica"> you want to start throwing -exceptions, there isn't a really good way to</FONT> -<BR><FONT FACE="Arial,Helvetica"> indicate that a constructor -has failed. If I had my way, I'd have a boolean</FONT> -<BR><FONT FACE="Arial,Helvetica"> return code from it that -would cause new to return 0 if I failed. Oh</FONT> -<BR><FONT FACE="Arial,Helvetica"> well...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Handler::Client_Handler (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our destructor doesn't do -anything either. That is also by design.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Remember, we really want -folks to use destroy() to get rid of us. If that's</FONT> -<BR><FONT FACE="Arial,Helvetica"> so, then there's nothing -left to do when the destructor gets invoked.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Handler::~Client_Handler (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The much talked about destroy() -method! The reason I keep going on about</FONT> -<BR><FONT FACE="Arial,Helvetica"> this is because it's just -a Bad Idea (TM) to do real work inside of a</FONT> -<BR><FONT FACE="Arial,Helvetica"> destructor. Although -this method is void, it really should return</FONT> -<BR><FONT FACE="Arial,Helvetica"> int so that it can tell the -caller there was a problem. Even as</FONT> -<BR><FONT FACE="Arial,Helvetica"> void you could at least throw -an exception which you would never want</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do in a destructor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">void Client_Handler::destroy (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We probably got -here because of an error on the stream, so the peer</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection is -probably already closed. Still... there are other ways to</FONT> -<BR><FONT FACE="Arial,Helvetica"> get here and -closing a closed peer doesn't hurt.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->peer ().close ();</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Tell the reactor -to forget all about us. Notice that we use the same args</FONT> -<BR><FONT FACE="Arial,Helvetica"> here that we -use in the open() method to register ourselves. In addition,</FONT> -<BR><FONT FACE="Arial,Helvetica"> we use the DONT_CALL -flag to prevent handle_close() being called. Since we</FONT> -<BR><FONT FACE="Arial,Helvetica"> likely got here -due to handle_close(), that could cause a bit of nasty</FONT> -<BR><FONT FACE="Arial,Helvetica"> recursion!</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->reactor ()->remove_handler -(this,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Event_Handler:: READ_MASK | ACE_Event_Handler::DONT_CALL);</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This is how we're -able to tell folks not to use delete. By</FONT> -<BR><FONT FACE="Arial,Helvetica"> deleting our -own instance, we take care of memory leaks after ensuring</FONT> -<BR><FONT FACE="Arial,Helvetica"> that the object -is shut down correctly.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> delete this;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As mentioned before, the -open() method is called by the Client_Acceptor when</FONT> -<BR><FONT FACE="Arial,Helvetica"> a new client connection has -been accepted. The Client_Acceptor instance</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer is cast to a void* -and given to us here. We'll use that to avoid</FONT> -<BR><FONT FACE="Arial,Helvetica"> some global data...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::open (void *_acceptor)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We need this -to store the address of the client that we are now connected</FONT> -<BR><FONT FACE="Arial,Helvetica"> to. We'll -use it later to display a debug message.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_INET_Addr addr;</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our ACE_Svc_Handler -baseclass gives us the peer() method as a way to</FONT> -<BR><FONT FACE="Arial,Helvetica"> access our underlying -ACE_SOCK_Stream. On that object, we can invoke the</FONT> -<BR><FONT FACE="Arial,Helvetica"> get_remote_addr() -method to get get an ACE_INET_Addr having our client's</FONT> -<BR><FONT FACE="Arial,Helvetica"> address information. -As with most ACE methods, we'll get back (and return)</FONT> -<BR><FONT FACE="Arial,Helvetica"> a -1 if there -was any kind of error. Once we have the ACE_INET_Addr, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> can query it -to find out the clien's host name, TCP/IP address, TCP/IP</FONT> -<BR><FONT FACE="Arial,Helvetica"> port value and -so forth. One word of warning: the get_host_name()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method of ACE_INET_Addr -may return you an empty string if your name server</FONT> -<BR><FONT FACE="Arial,Helvetica"> can't resolve -it. On the other hand, get_host_addr() will always give you</FONT> -<BR><FONT FACE="Arial,Helvetica"> the dotted-decimal -string representing the TCP/IP address.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (this->peer ().get_remote_addr -(addr) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return --1;</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Convert the void* -to a Client_Acceptor*. You should probably use those</FONT> -<BR><FONT FACE="Arial,Helvetica"> fancy new C++ -cast operators but I can never remember how/when to do so.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since you can -cast just about anything around a void* without compiler</FONT> -<BR><FONT FACE="Arial,Helvetica"> warnings be very -sure of what you're doing when you do this kind of thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> That's where -the new-style cast operators can save you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor *acceptor = (Client_Acceptor -*) _acceptor;</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our Client_Acceptor -is constructed with a concurrency strategy. Here, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> go back to it -to find out what that strategy was. If thread-per-connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> was selected -then we simply activate a thread for ourselves and exit. Our</FONT> -<BR><FONT FACE="Arial,Helvetica"> svc() method -will then begin executing in that thread.</FONT> - -<P><FONT FACE="Arial,Helvetica"> If we are told -to use the single-threaded strategy, there is no difference</FONT> -<BR><FONT FACE="Arial,Helvetica"> between this -and the Tutorial 5 implementation.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( acceptor->thread_per_connection() -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return this->activate();</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our reactor reference -will be set when we register ourselves but I decided</FONT> -<BR><FONT FACE="Arial,Helvetica"> to go ahead and -set it here. No good reason really...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->reactor (acceptor->reactor -());</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If we managed -to get the client's address then we're connected to a real</FONT> -<BR><FONT FACE="Arial,Helvetica"> and valid client. -I suppose that in some cases, the client may connect</FONT> -<BR><FONT FACE="Arial,Helvetica"> and disconnect -so quickly that it is invalid by the time we get here. In</FONT> -<BR><FONT FACE="Arial,Helvetica"> any case, the -test above should always be done to ensure that the</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection is -worth keeping.</FONT> - -<P><FONT FACE="Arial,Helvetica"> Now, regiser ourselves -with a reactor and tell that reactor that we want</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be notified -when there is something to read. Remember, we took our</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor value -from the acceptor which created us in the first place.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we're exploring -a single-threaded implementation, this is the</FONT> -<BR><FONT FACE="Arial,Helvetica"> correct thing -to do.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (this->reactor ()->register_handler -(this, ACE_Event_Handler::READ_MASK) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Here, we use -the ACE_INET_Addr object to print a message with the name of</FONT> -<BR><FONT FACE="Arial,Helvetica"> the client we're -connected to. Again, it is possible that you'll get an</FONT> -<BR><FONT FACE="Arial,Helvetica"> empty string -for the host name if your DNS isn't configured correctly or</FONT> -<BR><FONT FACE="Arial,Helvetica"> if there is some -other reason that a TCP/IP addreess cannot be converted</FONT> -<BR><FONT FACE="Arial,Helvetica"> into a host name.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) -connected with %s\n", addr.get_host_name ()));</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Always return -zero on success.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As mentioned in the header, -the typical way to close an object in a threaded</FONT> -<BR><FONT FACE="Arial,Helvetica"> context is to invoke it's -close() method. Since we already have a handle_close()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method built to cleanup after -us, we'll just forward the request on to that</FONT> -<BR><FONT FACE="Arial,Helvetica"> object.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::close(u_long flags)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Down in the depths of our baseclass, this will eventually cause us</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to be destroyed. Since all of the destructors are virtual, everything</FONT> -<BR><FONT FACE="Arial,Helvetica"> -gets cleaned up nicely.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this->handle_close(ACE_INVALID_HANDLE,0);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Don't forward the close() to the baseclass! handle_close() above -has</FONT> -<BR><FONT FACE="Arial,Helvetica"> -already taken care of delete'ing. Forwarding close() would cause -that</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to happen again and things would get really ugly at that point!</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In the open() method, we -registered with the reactor and requested to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> notified when there is data -to be read. When the reactor sees that activity</FONT> -<BR><FONT FACE="Arial,Helvetica"> it will invoke this handle_input() -method on us. As I mentioned, the _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter isn't useful to -us but it narrows the list of methods the reactor</FONT> -<BR><FONT FACE="Arial,Helvetica"> has to worry about and the -list of possible virtual functions we would have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to override.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::handle_input (ACE_HANDLE -_handle)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Some compilers -don't like it when you fail to use a parameter. This macro</FONT> -<BR><FONT FACE="Arial,Helvetica"> will keep 'em -quiet for you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_handle);</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Now, we create -and initialize a buffer for receiving the data. Since this</FONT> -<BR><FONT FACE="Arial,Helvetica"> is just a simple -test app, we'll use a small buffer size.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, 0, sizeof (buf));</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Invoke the process() -method with a pointer to our data area. We'll let</FONT> -<BR><FONT FACE="Arial,Helvetica"> that method worry -about interfacing with the data. You might choose to go</FONT> -<BR><FONT FACE="Arial,Helvetica"> ahead and read -the data and then pass the result to process(). However,</FONT> -<BR><FONT FACE="Arial,Helvetica"> application logic -may require that you read a few bytes to determine what</FONT> -<BR><FONT FACE="Arial,Helvetica"> else to read... -It's best if we push that all into the application-logic</FONT> -<BR><FONT FACE="Arial,Helvetica"> level.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> return this->process (buf, sizeof -(buf));</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If we return -1 out of handle_input() -or if the reactor sees other problems</FONT> -<BR><FONT FACE="Arial,Helvetica"> with us then handle_close() -will be called. It uses our destroy() method to</FONT> -<BR><FONT FACE="Arial,Helvetica"> shut us down cleanly and -get rid of our instance.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::handle_close (ACE_HANDLE -_handle, ACE_Reactor_Mask _mask)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_handle);</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_mask);</FONT> - -<P><FONT FACE="Arial,Helvetica"> this->destroy ();</FONT> -<BR><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The ACE_Svc_Handler<> -is ultimately derived from ACE_Task<>. If you want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> create a multi-threaded application, -these are your tools! Simply override</FONT> -<BR><FONT FACE="Arial,Helvetica"> the svc() method in your -derivative and arrange for your activate() method</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be called. The svc() -method then executes in the new thread.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::svc(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Like handle_input(), -we create a buffer for loading the data. Doing so</FONT> -<BR><FONT FACE="Arial,Helvetica"> in handle_input() -doesn't help any but there is a small performance increase</FONT> -<BR><FONT FACE="Arial,Helvetica"> by doing this -here: the buffer is created once when the thread is created</FONT> -<BR><FONT FACE="Arial,Helvetica"> instead of for -each invocation of process().</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> - -<P><FONT FACE="Arial,Helvetica"> // Forever...</FONT> -<BR><FONT FACE="Arial,Helvetica"> while( 1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> // Clean the -buffer...</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, -0, sizeof (buf));</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Invoke the proces() method to read and process the data. This is</FONT> -<BR><FONT FACE="Arial,Helvetica"> -exactly the way it is used by handle_input(). That's the reason I</FONT> -<BR><FONT FACE="Arial,Helvetica"> -created process() in the first place: so that it can be used in either</FONT> -<BR><FONT FACE="Arial,Helvetica"> -concurrency strategy. Since process() has all of our application-level</FONT> -<BR><FONT FACE="Arial,Helvetica"> -logic, it's nice that it doesn't have to change when we decide to go</FONT> -<BR><FONT FACE="Arial,Helvetica"> -multi-threaded.</FONT> - -<P><FONT FACE="Arial,Helvetica"> -Notice that since the recv() method call in process() blocks until</FONT> -<BR><FONT FACE="Arial,Helvetica"> -there is data ready, this thread doesn't consume any CPU time until</FONT> -<BR><FONT FACE="Arial,Helvetica"> -there is actually data sent from the client.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( this->process(buf,sizeof(buf)) -== -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return(-1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> return(0);</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> And, at last, we get to the -application-logic level. Out of everything</FONT> -<BR><FONT FACE="Arial,Helvetica"> we've done so far, this is -the only thing that really has anything to do</FONT> -<BR><FONT FACE="Arial,Helvetica"> with what your application -will do. In this method we will read and process</FONT> -<BR><FONT FACE="Arial,Helvetica"> the client's data. -In a real appliation, you will probably have a bit more</FONT> -<BR><FONT FACE="Arial,Helvetica"> in main() to deal with command -line options but after that point, all of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> action takes place here.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::process (char *_rdbuf, -int _rdbuf_len)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Using the buffer -provided for us, we read the data from the client. If</FONT> -<BR><FONT FACE="Arial,Helvetica"> there is a read -error (eg -- recv() returns -1) then it's a pretty good</FONT> -<BR><FONT FACE="Arial,Helvetica"> bet that the -connection is gone. Likewise, if we read zero bytes then</FONT> -<BR><FONT FACE="Arial,Helvetica"> something wrong -has happened. The reactor wouldn't have called us if</FONT> -<BR><FONT FACE="Arial,Helvetica"> there wasn't -some kind of read activity but there wouldn't be activity if</FONT> -<BR><FONT FACE="Arial,Helvetica"> there were no -bytes to read...</FONT> - -<P><FONT FACE="Arial,Helvetica"> On the other hand, -if we got some data then we can display it in a debug</FONT> -<BR><FONT FACE="Arial,Helvetica"> message for everyone -to see.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> switch (this->peer ().recv (_rdbuf, -_rdbuf_len))</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> case -1:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> case 0:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), --1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> default:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG -((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf));</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Well, that's it! After all the talk & the hype, you would -have expected it to be more difficult to create a multi-threaded server. -Surprise! It really is that easy. You still have to handle -contention issues which we haven't addressed here and that is a rather -nasty topic. Still, for the simple case, this is all you have to -do. - -<P>The next page is the last for this tutorial. Head on over there -& we'll round up the file list one last time. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page06.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/006/page06.html b/docs/tutorials/006/page06.html deleted file mode 100644 index b4ad640b25e..00000000000 --- a/docs/tutorials/006/page06.html +++ /dev/null @@ -1,52 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 006</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>That's it for Tutorial 6. With very little effort we've managed -to extend the previous single-threaded server to an implementation which -allows runtime selection of single or multi-threaded operation. In -Tutorial 7 we'll extend that again to allow a thread-pool choice in addition -to the current two. - -<P>For reference, here's the file list again: -<UL> -<LI> -<A HREF="Makefile">Makefile</A></LI> - -<LI> -<A HREF="client_acceptor.h">client_acceptor.h</A></LI> - -<LI> -<A HREF="client_handler.cpp">client_handler.cpp</A></LI> - -<LI> -<A HREF="client_handler.h">client_handler.h</A></LI> - -<LI> -<A HREF="server.cpp">server.cpp</A></LI> - -<LI> -<A HREF="fix.Makefile">fix.Makefile</A></LI> -</UL> - - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="../../tutorials">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/006/server.cpp b/docs/tutorials/006/server.cpp deleted file mode 100644 index 5195f46f8d0..00000000000 --- a/docs/tutorials/006/server.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// $Id$ - -/* - We try to keep main() very simple. One of the ways we do that is to push - much of the complicated stuff into worker objects. In this case, we only - need to include the acceptor header in our main source file. We let it - worry about the "real work". - */ - -#include "client_acceptor.h" - -/* - As before, we create a simple signal handler that will set our finished - flag. There are, of course, more elegant ways to handle program shutdown - requests but that isn't really our focus right now, so we'll just do the - easiest thing. - */ - -static sig_atomic_t finished = 0; -extern "C" void handler (int) -{ - finished = 1; -} - -/* - A server has to listen for clients at a known TCP/IP port. The default ACE - port is 10002 (at least on my system) and that's good enough for what we - want to do here. Obviously, a more robust application would take a command - line parameter or read from a configuration file or do some other clever - thing. Just like the signal handler above, though, that's what we want to - focus on, so we're taking the easy way out. - */ - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -/* - Finally, we get to main. Some C++ compilers will complain loudly if your - function signature doesn't match the prototype. Even though we're not - going to use the parameters, we still have to specify them. - */ - -int main (int argc, char *argv[]) -{ -/* - In our earlier servers, we used a global pointer to get to the reactor. I've - never really liked that idea, so I've moved it into main() this time. When - we get to the Client_Handler object you'll see how we manage to get a - pointer back to this reactor. - */ - ACE_Reactor reactor; - - /* - The acceptor will take care of letting clients connect to us. It will - also arrange for a Client_Handler to be created for each new client. - Since we're only going to listen at one TCP/IP port, we only need one - acceptor. If we wanted, though, we could create several of these and - listen at several ports. (That's what we would do if we wanted to rewrite - inetd for instance.) - */ - Client_Acceptor peer_acceptor; - - /* - Create an ACE_INET_Addr that represents our endpoint of a connection. We - then open our acceptor object with that Addr. Doing so tells the acceptor - where to listen for connections. Servers generally listen at "well known" - addresses. If not, there must be some mechanism by which the client is - informed of the server's address. - - Note how ACE_ERROR_RETURN is used if we fail to open the acceptor. This - technique is used over and over again in our tutorials. - */ - if (peer_acceptor.open (ACE_INET_Addr (PORT), &reactor) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - - /* - As with Tutorial 5, we know that we're now registered with our reactor - so we don't have to mess with that step. - */ - - /* - Install our signal handler. You can actually register signal handlers - with the reactor. You might do that when the signal handler is - responsible for performing "real" work. Our simple flag-setter doesn't - justify deriving from ACE_Event_Handler and providing a callback function - though. - */ - ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - /* - Like ACE_ERROR_RETURN, the ACE_DEBUG macro gets used quite a bit. It's a - handy way to generate uniform debug output from your program. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server daemon\n")); - - /* - This will loop "forever" invoking the handle_events() method of our - reactor. handle_events() watches for activity on any registered handlers - and invokes their appropriate callbacks when necessary. Callback-driven - programming is a big thing in ACE, you should get used to it. If the - signal handler catches something, the finished flag will be set and we'll - exit. Conveniently enough, handle_events() is also interrupted by signals - and will exit back to the while() loop. (If you want your event loop to - not be interrupted by signals, checkout the <i>restart</i> flag on the - open() method of ACE_Reactor if you're interested.) - */ - while (!finished) - reactor.handle_events (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server daemon\n")); - - return 0; -} - -#if !defined(ACE_HAS_GNU_REPO) -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ -#endif /* ACE_HAS_GNU_REPO */ diff --git a/docs/tutorials/007/Makefile b/docs/tutorials/007/Makefile deleted file mode 100644 index be02b45ed33..00000000000 --- a/docs/tutorials/007/Makefile +++ /dev/null @@ -1,101 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -# You can generally find a Makefile in the ACE examples, tests or the library -# itself that will satisfy our application needs. This one was taken from -# one of the examples. - - # Define the name of the binary we want to create. There has to be - # a CPP file $(BIN).cpp but it doesn't necessarily have to have your - # main() in it. Most of the time, though, it will. -BIN = server - - # Few applications will have a single source file. We use the FILES - # macro to build up a list of additional files to compile. Notice - # that we leave off the extension just as with BIN -FILES = -FILES += client_handler -FILES += client_acceptor -FILES += thread_pool - - # The BUILD macro is used by the ACE makefiles. Basically, it tells - # the system what to build. I don't really know what VBIN is other - # than it is constructed from the value of BIN. Just go with it... -BUILD = $(VBIN) - - # Here we use some GNU make extensions to build the SRC macro. Basically, - # we're just adding .cpp to the value of BIN and for each entry of the - # FILES macro. -SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES)) - - # This is used by my Indent target below. It's not a part of standard - # ACE and you don't need it yourself. -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - - # This is where the real power lies! These included makefile components - # are similar to the C++ templates in ACE. That is, they do a tremendous - # amount of work for you and all you have to do is include them. - # As a matter of fact, in our project, I created a single file named - # "app.mk" that includes all of these. Our project makefiles then just - # need to include app.mk to get everything they need. - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - - # Sometimes I like to reformat my code to make it more readable. This is - # more useful for the comments than anything else. Unfortunately, the - # "indent" program doesn't quite grok C++ so I have to post-process it's - # output just a bit. -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - - # One of the targets in the ACE makefiles is "depend". It will invoke - # your compiler in a way that will generate a list of dependencies for - # you. This is a great thing! Unfortunately, it puts all of that mess - # directly into the Makefile. I prefer my Makefile to stay clean and - # uncluttered. The perl script referenced here pulls the dependency - # stuff back out of the Makefile and into a file ".depend" which we then - # include just like the makefile components above. -Depend : depend - perl fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - - # Don't put anything below here. Between the "depend" target and fix.Makefile - # it's guaranteed to be lost! - - # This is inserted by the fix.Makefile script -include .depend diff --git a/docs/tutorials/007/client_acceptor.cpp b/docs/tutorials/007/client_acceptor.cpp deleted file mode 100644 index 6cc90612558..00000000000 --- a/docs/tutorials/007/client_acceptor.cpp +++ /dev/null @@ -1,67 +0,0 @@ - -// $Id$ - -#include "client_acceptor.h" - -/* - Construct ourselves with the chosen concurrency strategy. Notice that we also - set our Thread_Pool reference to our private instance. - */ -Client_Acceptor::Client_Acceptor( int _concurrency ) - : concurrency_(_concurrency) - ,the_thread_pool_(private_thread_pool_) -{ -} - -/* - Construct ourselves with a reference to somebody else' Thread_Pool. Obvioulsy - our concurrency strategy is "thread_pool_" at this point. - */ -Client_Acceptor::Client_Acceptor( Thread_Pool & _thread_pool ) - : concurrency_(thread_pool_) - ,the_thread_pool_(_thread_pool) -{ -} - -/* - When we're destructed, we may need to cleanup after ourselves. If we're running - with a thread pool that we own, it is up to us to close it down. - */ -Client_Acceptor::~Client_Acceptor( void ) -{ - if( this->concurrency() == thread_pool_ && thread_pool_is_private() ) - { - thread_pool()->close(); - } -} - -/* - Similar to the destructor (and close() below) it is necessary for us to open the - thread pool in some circumstances. - - Notice how we delegate most of the open() work to the open() method of our baseclass. - */ -int Client_Acceptor::open( const ACE_INET_Addr & _addr, ACE_Reactor * _reactor, int _pool_size ) -{ - if( this->concurrency() == thread_pool_ && thread_pool_is_private() ) - { - thread_pool()->open(_pool_size); - } - - return inherited::open(_addr,_reactor); -} - -/* - Here again we find that we have to manage the thread pool. Like open() we also delegate - the other work to our baseclass. - */ -int Client_Acceptor::close(void) -{ - if( this->concurrency() == thread_pool_ && thread_pool_is_private() ) - { - thread_pool()->close(); - } - - return inherited::close(); -} - diff --git a/docs/tutorials/007/client_acceptor.h b/docs/tutorials/007/client_acceptor.h deleted file mode 100644 index 82c761879ea..00000000000 --- a/docs/tutorials/007/client_acceptor.h +++ /dev/null @@ -1,141 +0,0 @@ - -// $Id$ - -#ifndef CLIENT_ACCEPTOR_H -#define CLIENT_ACCEPTOR_H - -/* - The ACE_Acceptor<> template lives in the ace/Acceptor.h header file. You'll - find a very consitent naming convention between the ACE objects and the - headers where they can be found. In general, the ACE object ACE_Foobar will - be found in ace/Foobar.h. - */ - -#include "ace/Acceptor.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -/* - Since we want to work with sockets, we'll need a SOCK_Acceptor to allow the - clients to connect to us. - */ -#include "ace/SOCK_Acceptor.h" - -/* - The Client_Handler object we develop will be used to handle clients once - they're connected. The ACE_Acceptor<> template's first parameter requires - such an object. In some cases, you can get by with just a forward - declaration on the class, in others you have to have the whole thing. - */ -#include "client_handler.h" - -/* - Parameterize the ACE_Acceptor<> such that it will listen for socket - connection attempts and create Client_Handler objects when they happen. In - Tutorial 001, we wrote the basic acceptor logic on our own before we - realized that ACE_Acceptor<> was available. You'll get spoiled using the - ACE templates because they take away a lot of the tedious details! - */ -typedef ACE_Acceptor < Client_Handler, ACE_SOCK_ACCEPTOR > Client_Acceptor_Base; - -#include "thread_pool.h" - -/* - This time we've added quite a bit more to our acceptor. In addition to - providing a choice of concurrency strategies, we also maintain a Thread_Pool - object in case that strategy is chosen. The object still isn't very complex - but it's come a long way from the simple typedef we had in Tutorial 5. - - Why keep the thread pool as a member? If we go back to the inetd concept - you'll recall that we need several acceptors to make that work. We may have - a situation in which our different client types requre different resources. - That is, we may need a large thread pool for some client types and a smaller - one for others. We could share a pool but then the client types may have - undesirable impact on one another. - - Just in case you do want to share a single thread pool, there is a constructor - below that will let you do that. - */ -class Client_Acceptor : public Client_Acceptor_Base -{ -public: - typedef Client_Acceptor_Base inherited; - - /* - Now that we have more than two strategies, we need more than a boolean - to tell us what we're using. A set of enums is a good choice because - it allows us to use named values. Another option would be a set of - static const integers. - */ - enum concurrency_t - { - single_threaded_, - thread_per_connection_, - thread_pool_ - }; - - /* - The default constructor allows the programmer to choose the concurrency - strategy. Since we want to focus on thread-pool, that's what we'll use - if nothing is specified. - */ - Client_Acceptor( int _concurrency = thread_pool_ ); - - /* - Another option is to construct the object with an existing thread pool. - The concurrency strategy is pretty obvious at that point. - */ - Client_Acceptor( Thread_Pool & _thread_pool ); - - /* - Our destructor will take care of shutting down the thread-pool - if applicable. - */ - ~Client_Acceptor( void ); - - /* - Open ourselves and register with the given reactor. The thread pool size - can be specified here if you want to use that concurrency strategy. - */ - int open( const ACE_INET_Addr & _addr, ACE_Reactor * _reactor, - int _pool_size = Thread_Pool::default_pool_size_ ); - - /* - Close ourselves and our thread pool if applicable - */ - int close(void); - - /* - What is our concurrency strategy? - */ - int concurrency(void) - { return this->concurrency_; } - - /* - Give back a pointer to our thread pool. Our Client_Handler objects - will need this so that their handle_input() methods can put themselves - into the pool. Another alternative would be a globally accessible - thread pool. ACE_Singleton<> is a way to achieve that. - */ - Thread_Pool * thread_pool(void) - { return & this->the_thread_pool_; } - - /* - Since we can be constructed with a Thread_Pool reference, there are times - when we need to know if the thread pool we're using is ours or if we're - just borrowing it from somebody else. - */ - int thread_pool_is_private(void) - { return &the_thread_pool_ == &private_thread_pool_; } - -protected: - int concurrency_; - - Thread_Pool private_thread_pool_; - - Thread_Pool & the_thread_pool_; -}; - -#endif // CLIENT_ACCEPTOR_H diff --git a/docs/tutorials/007/client_handler.cpp b/docs/tutorials/007/client_handler.cpp deleted file mode 100644 index 39c4395967c..00000000000 --- a/docs/tutorials/007/client_handler.cpp +++ /dev/null @@ -1,230 +0,0 @@ - -// $Id$ - -/* - Since this is the third time we've seen most of this, I'm going to strip out almost - all of the comments that you've already seen. That way, you can concentrate on the - new items. - */ - -#include "client_acceptor.h" -#include "client_handler.h" - -/* - We're going to be registering and unregistering a couple of times. To make sure that - we use the same flags every time, I've created these handy macros. - */ -#define REGISTER_MASK ACE_Event_Handler::READ_MASK -#define REMOVE_MASK (ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL) - -/* - Our constructor still doesn't really do anything. We simply initialize the acceptor - pointer to "null" and get our current thread id. The static self() method of ACE_Thread - will return you a thread id native to your platform. - */ -Client_Handler::Client_Handler (void) - : client_acceptor_(0) - ,creator_(ACE_Thread::self()) -{ -} - -Client_Handler::~Client_Handler (void) -{ -} - -/* - Query our acceptor for the concurrency strategy. Notice that we don't bother - to check that our acceptor pointer is valid. That is proably a bad idea... - */ -int Client_Handler::concurrency(void) -{ - return this->client_acceptor()->concurrency(); -} - -/* - And here we ask the acceptor about the thread pool. - */ -Thread_Pool * Client_Handler::thread_pool(void) -{ - return this->client_acceptor()->thread_pool(); -} - -/* - The destroy() method hasn't changed since we wrote it back in Tutorial 5. - */ -void Client_Handler::destroy (void) -{ - this->peer ().close (); - - this->reactor ()->remove_handler (this, REMOVE_MASK ); - - delete this; -} - -/* - Back to our open() method. This is straight out of Tutorial 6. There's - nothing additional here for the thread-pool implementation. - */ -int Client_Handler::open (void *_acceptor) -{ - client_acceptor( (Client_Acceptor *) _acceptor ); - - if( concurrency() == Client_Acceptor::thread_per_connection_ ) - { - return this->activate(); - } - - this->reactor (client_acceptor()->reactor ()); - - ACE_INET_Addr addr; - - if (this->peer ().get_remote_addr (addr) == -1) - { - return -1; - } - - if (this->reactor ()->register_handler (this, REGISTER_MASK) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); - } - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name ())); - - return 0; -} - -/* - As mentioned in the header, the typical way to close an object in a threaded - context is to invoke it's close() method. Since we already have a handle_close() - method built to cleanup after us, we'll just forward the request on to that - object. - */ -int Client_Handler::close(u_long flags) -{ - this->handle_close(ACE_INVALID_HANDLE,0); - - /* - After we've taken care of ourselves, call the baseclass method - to do any other necessary cleanup. - */ - return inherited::close(); -} - -/* - In the open() method, we registered with the reactor and requested to be - notified when there is data to be read. When the reactor sees that activity - it will invoke this handle_input() method on us. As I mentioned, the _handle - parameter isn't useful to us but it narrows the list of methods the reactor - has to worry about and the list of possible virtual functions we would have - to override. - - You've read that much before... Now we have to do some extra stuff in case - we're using the thread-pool implementation. If we're called by our creator - thread then we must be in the reactor. In that case, we arrange to be put - into the thread pool. If we're not in the creator thread then we must be - in the thread pool and we can do some work. - */ -int Client_Handler::handle_input (ACE_HANDLE _handle) -{ - ACE_UNUSED_ARG (_handle); - - /* - Check our strategy. If we're using the thread pool and we're in the creation - thread then we know we were called by the reactor. - */ - if( concurrency() == Client_Acceptor::thread_pool_ ) - { - if( ACE_OS::thr_equal(ACE_Thread::self(),creator_) ) - { - /* - Remove ourselves from the reactor and ask to be put into the thread pool's - queue of work. (You should be able to use suspend_handler() but I've had - problems with that.) - */ - this->reactor()->remove_handler( this, REMOVE_MASK ); - return this->thread_pool()->enqueue(this); - } - } - - /* - Any strategy other than thread-per-connection will eventually get here. If we're in the - single-threaded implementation or the thread-pool, we still have to pass this way. - */ - - char buf[128]; - ACE_OS::memset (buf, 0, sizeof (buf)); - - /* - Invoke the process() method to do the work but save it's return value instead - of returning it immediately. - */ - - int rval = this->process(buf,sizeof(buf)); - - /* - Now, we look again to see if we're in the thread-pool implementation. If so then we - need to re-register ourselves with the reactor so that we can get more work when it - is available. (If suspend_handler() worked then we would use resume_handler() here.) - */ - if( concurrency() == Client_Acceptor::thread_pool_ ) - { - if( rval != -1 ) - { - this->reactor()->register_handler( this, REGISTER_MASK ); - } - } - - /* - Return the result of process() - */ - return(rval); -} - -int Client_Handler::handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask) -{ - ACE_UNUSED_ARG (_handle); - ACE_UNUSED_ARG (_mask); - - this->destroy (); - return 0; -} - -/* - Remember that when we leave our svc() method, the framework will take care - of calling our close() method so that we can cleanup after ourselves. - */ -int Client_Handler::svc(void) -{ - char buf[128]; - ACE_OS::memset (buf, 0, sizeof (buf)); - - while( 1 ) - { - if( this->process(buf,sizeof(buf)) == -1 ) - { - return(-1); - } - } - - return(0); -} - -/* - Once again, we see that the application-level logic has not been at all affected - by our choice of threading models. Of course, I'm not sharing data between threads - or anything. We'll leave locking issues for a later tutorial. - */ -int Client_Handler::process (char *_rdbuf, int _rdbuf_len) -{ - switch (this->peer ().recv (_rdbuf, _rdbuf_len)) - { - case -1: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1); - case 0: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), -1); - default: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf)); - } - - return 0; -} diff --git a/docs/tutorials/007/client_handler.h b/docs/tutorials/007/client_handler.h deleted file mode 100644 index 57fd5e033d2..00000000000 --- a/docs/tutorials/007/client_handler.h +++ /dev/null @@ -1,169 +0,0 @@ - -// $Id$ - -#ifndef CLIENT_HANDLER_H -#define CLIENT_HANDLER_H - -/* - Our client handler must exist somewhere in the ACE_Event_Handler object - hierarchy. This is a requirement of the ACE_Reactor because it maintains - ACE_Event_Handler pointers for each registered event handler. You could - derive our Client_Handler directly from ACE_Event_Handler but you still have - to have an ACE_SOCK_Stream for the actually connection. With a direct - derivative of ACE_Event_Handler, you'll have to contain and maintain an - ACE_SOCK_Stream instance yourself. With ACE_Svc_Handler (which is a - derivative of ACE_Event_Handler) some of those details are handled for you. - */ - -#include "ace/Svc_Handler.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "ace/SOCK_Stream.h" - -class Client_Acceptor; -class Thread_Pool; - -/* - Another feature of ACE_Svc_Handler is it's ability to present the ACE_Task<> - interface as well. That's what the ACE_NULL_SYNCH parameter below is all - about. That's beyond our scope here but we'll come back to it in the next - tutorial when we start looking at concurrency options. - */ -class Client_Handler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > -{ -public: - typedef ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > inherited; - - // Constructor... - Client_Handler (void); - - /* - The destroy() method is our preferred method of destruction. We could - have overloaded the delete operator but that is neither easy nor - intuitive (at least to me). Instead, we provide a new method of - destruction and we make our destructor protected so that only ourselves, - our derivatives and our friends can delete us. It's a nice - compromise. - */ - void destroy (void); - - /* - Most ACE objects have an open() method. That's how you make them ready - to do work. ACE_Event_Handler has a virtual open() method which allows us - to create this overrride. ACE_Acceptor<> will invoke this method after - creating a new Client_Handler when a client connects. Notice that the - parameter to open() is a void*. It just so happens that the pointer - points to the acceptor which created us. You would like for the parameter - to be an ACE_Acceptor<>* but since ACE_Event_Handler is generic, that - would tie it too closely to the ACE_Acceptor<> set of objects. In our - definition of open() you'll see how we get around that. - */ - int open (void *_acceptor); - - /* - When an ACE_Task<> object falls out of the svc() method, the framework - will call the close() method. That's where we want to cleanup ourselves - if we're running in either thread-per-connection or thread-pool mode. - */ - int close(u_long flags = 0); - - /* - When there is activity on a registered handler, the handle_input() method - of the handler will be invoked. If that method returns an error code (eg - -- -1) then the reactor will invoke handle_close() to allow the object to - clean itself up. Since an event handler can be registered for more than - one type of callback, the callback mask is provided to inform - handle_close() exactly which method failed. That way, you don't have to - maintain state information between your handle_* method calls. The _handle - parameter is explained below... - */ - int handle_close (ACE_HANDLE _handle, ACE_Reactor_Mask _mask); - - /* - When we register with the reactor, we're going to tell it that we want to - be notified of READ events. When the reactor sees that there is read - activity for us, our handle_input() will be invoked. The _handleg - provided is the handle (file descriptor in Unix) of the actual connection - causing the activity. Since we're derived from ACE_Svc_Handler<> and it - maintains it's own peer (ACE_SOCK_Stream) object, this is redundant for - us. However, if we had been derived directly from ACE_Event_Handler, we - may have chosen not to contain the peer. In that case, the _handleg - would be important to us for reading the client's data. - */ - int handle_input (ACE_HANDLE _handle); - -protected: - - /* - If the Client_Acceptor which created us has chosen a thread-per-connection - strategy then our open() method will activate us into a dedicate thread. - The svc() method will then execute in that thread performing some of the - functions we used to leave up to the reactor. - */ - int svc(void); - - /* - This has nothing at all to do with ACE. I've added this here as a worker - function which I will call from handle_input(). That allows me to - introduce concurrencly in later tutorials with a no changes to the worker - function. You can think of process() as application-level code and - everything elase as application-framework code. - */ - int process (char *_rdbuf, int _rdbuf_len); - - /* - We don't really do anything in our destructor but we've declared it to be - protected to prevent casual deletion of this object. As I said above, I - really would prefer that everyone goes through the destroy() method to get - rid of us. - */ - ~Client_Handler (void); - - /* - When we get to the definition of Client_Handler we'll see that there are - several places where we go back to the Client_Acceptor for information. - It is generally a good idea to do that through an accesor rather than - using the member variable directly. - */ - Client_Acceptor * client_acceptor( void ) - { return this->client_acceptor_; } - - /* - And since you shouldn't access a member variable directly, neither should you - set (mutate) it. Although it might seem silly to do it this way, you'll thank - yourself for it later. - */ - void client_acceptor( Client_Acceptor * _client_acceptor ) - { this->client_acceptor_ = _client_acceptor; } - - /* - The concurrency() accessor tells us the current concurrency strategy. It actually - queries the Client_Acceptor for it but by having the accessor in place, we could - change our implementation without affecting everything that needs to know. - */ - int concurrency(void); - - /* - Likewise for access to the Thread_Pool that we belong to. - */ - Thread_Pool * thread_pool(void); - - - Client_Acceptor * client_acceptor_; - - /* - For some reason I didn't create accessor/mutator methods for this. So much for - consistency.... - - This variable is used to remember the thread in which we were created: the "creator" - thread in other words. handle_input() needs to know if it is operating in the - main reactor thread (which is the one that created us) or if it is operating in - one of the thread pool threads. More on this when we get to handle_input(). - */ - ACE_thread_t creator_; -}; - -#endif // CLIENT_HANDLER_H diff --git a/docs/tutorials/007/fix.Makefile b/docs/tutorials/007/fix.Makefile deleted file mode 100755 index e99c194114a..00000000000 --- a/docs/tutorials/007/fix.Makefile +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/perl - - # Open the Makefile that has been mangled by 'make depend' - # and suck it into a perl array. -open(IF,"<Makefile") || die; -@makefile = <IF>; -close(IF); - - # Now open our .depend file and a temporary Makefile. - # We'll split the original Makefile between these two. -open(DF,">.depend") || die; -open(MF,">Makefile.tmp") || die; - - # For each line we read out of the original file... -foreach (@makefile) { - - # If we're into the dependency section, write the line - # into the .depend file. - # - if( $depend ) { - print DF $_; - } - else { - # If we haven't gotten to the dependency section yet - # then see if the current line is the separator that - # "make depend" causes to be inserted. - # - if( m/^\Q# DO NOT DELETE THIS LINE -- g++dep uses it.\E/ ) { - - # If so, change our "mode" and skip this line. - ++$depend; - next; - } - - # Also skip the "include .depend" that we insert. If we - # don't do this, it is possible to have a bunch of these - # inserted into the output when we read an unmangled Makefile - next if( m/^include .depend/ ); - - # Print the non-dependency info to the temporary Makefile - print MF $_; - } -} - -# Tell our new Makefile to include the dependency file -print MF "include .depend\n"; - -# Close the two output files... -close(DF); -close(MF); - -# Unlink (remove) the original Makefile and rename our -# temporary file. There's obviously room for error checking -# here but we've got the Makefile checked into some revision -# control system anyway. Don't we? - -unlink("Makefile"); -rename("Makefile.tmp","Makefile"); - -exit(0); diff --git a/docs/tutorials/007/page01.html b/docs/tutorials/007/page01.html deleted file mode 100644 index 9402426de3f..00000000000 --- a/docs/tutorials/007/page01.html +++ /dev/null @@ -1,33 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 007</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In this tutorial, we're going to extend Tutorial 6 to add a third concurrency -strategy: thread-pool. Like Tutorail 6 did to Tutorial 5, we're -going to keep the existing strategies that we've already created and add -this one in as a "bonus". As you'll see, our basic objects will change -but not by a whole lot. To accomplish this, we'll introduce one new -major object that helps to abstract the thread pool concept. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/007/page02.html b/docs/tutorials/007/page02.html deleted file mode 100644 index c6e7bedec43..00000000000 --- a/docs/tutorials/007/page02.html +++ /dev/null @@ -1,197 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 007</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>As usualy, we start with <A HREF="server.cpp">server.cpp</A> -<BR> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: server.cpp,v 1.1 1998/08/30 16:04:12 -jcej Exp $</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We try to keep main() very -simple. One of the ways we do that is to push</FONT> -<BR><FONT FACE="Arial,Helvetica"> much of the complicated stuff -into worker objects. In this case, we only</FONT> -<BR><FONT FACE="Arial,Helvetica"> need to include the acceptor -header in our main source file. We let it</FONT> -<BR><FONT FACE="Arial,Helvetica"> worry about the "real work".</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> - -<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As before, we create a simple -signal handler that will set our finished</FONT> -<BR><FONT FACE="Arial,Helvetica"> flag. There are, of -course, more elegant ways to handle program shutdown</FONT> -<BR><FONT FACE="Arial,Helvetica"> requests but that isn't really -our focus right now, so we'll just do the</FONT> -<BR><FONT FACE="Arial,Helvetica"> easiest thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> - -<P><FONT FACE="Arial,Helvetica">static sig_atomic_t finished = 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">extern "C" void handler (int)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> finished = 1;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> A server has to listen for -clients at a known TCP/IP port. The default ACE</FONT> -<BR><FONT FACE="Arial,Helvetica"> port is 10002 (at least on -my system) and that's good enough for what we</FONT> -<BR><FONT FACE="Arial,Helvetica"> want to do here. Obviously, -a more robust application would take a command</FONT> -<BR><FONT FACE="Arial,Helvetica"> line parameter or read from -a configuration file or do some other clever</FONT> -<BR><FONT FACE="Arial,Helvetica"> thing. Just like the -signal handler above, though, that's what we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> focus on, so we're taking -the easy way out.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> - -<P><FONT FACE="Arial,Helvetica">static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Finally, we get to main. -Some C++ compilers will complain loudly if your</FONT> -<BR><FONT FACE="Arial,Helvetica"> function signature doesn't -match the prototype. Even though we're not</FONT> -<BR><FONT FACE="Arial,Helvetica"> going to use the parameters, -we still have to specify them.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> - -<P><FONT FACE="Arial,Helvetica">int main (int argc, char *argv[])</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In our earlier servers, we -used a global pointer to get to the reactor. I've</FONT> -<BR><FONT FACE="Arial,Helvetica"> never really liked that idea, -so I've moved it into main() this time. When</FONT> -<BR><FONT FACE="Arial,Helvetica"> we get to the Client_Handler -object you'll see how we manage to get a</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer back to this reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Reactor reactor;</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The acceptor -will take care of letting clients connect to us. It will</FONT> -<BR><FONT FACE="Arial,Helvetica"> also arrange -for a Client_Handler to be created for each new client.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we're only -going to listen at one TCP/IP port, we only need one</FONT> -<BR><FONT FACE="Arial,Helvetica"> acceptor. -If we wanted, though, we could create several of these and</FONT> -<BR><FONT FACE="Arial,Helvetica"> listen at several -ports. (That's what we would do if we wanted to rewrite</FONT> -<BR><FONT FACE="Arial,Helvetica"> inetd for -instance.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor peer_acceptor;</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Create an ACE_INET_Addr -that represents our endpoint of a connection. We</FONT> -<BR><FONT FACE="Arial,Helvetica"> then open our -acceptor object with that Addr. Doing so tells the acceptor</FONT> -<BR><FONT FACE="Arial,Helvetica"> where to listen -for connections. Servers generally listen at "well known"</FONT> -<BR><FONT FACE="Arial,Helvetica"> addresses. -If not, there must be some mechanism by which the client is</FONT> -<BR><FONT FACE="Arial,Helvetica"> informed of the -server's address.</FONT> - -<P><FONT FACE="Arial,Helvetica"> Note how ACE_ERROR_RETURN -is used if we fail to open the acceptor. This</FONT> -<BR><FONT FACE="Arial,Helvetica"> technique is -used over and over again in our tutorials.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (peer_acceptor.open (ACE_INET_Addr -(PORT), &reactor) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN ((LM_ERROR, -"%p\n", "open"), -1);</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Install our signal -handler. You can actually register signal handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> with the reactor. -You might do that when the signal handler is</FONT> -<BR><FONT FACE="Arial,Helvetica"> responsible for -performing "real" work. Our simple flag-setter doesn't</FONT> -<BR><FONT FACE="Arial,Helvetica"> justify deriving -from ACE_Event_Handler and providing a callback function</FONT> -<BR><FONT FACE="Arial,Helvetica"> though.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Sig_Action sa ((ACE_SignalHandler) -handler, SIGINT);</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Like ACE_ERROR_RETURN, -the ACE_DEBUG macro gets used quite a bit. It's a</FONT> -<BR><FONT FACE="Arial,Helvetica"> handy way to -generate uniform debug output from your program.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) -starting up server daemon\n"));</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This will loop -"forever" invoking the handle_events() method of our</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor. handle_events() -watches for activity on any registered handlers</FONT> -<BR><FONT FACE="Arial,Helvetica"> and invokes their -appropriate callbacks when necessary. Callback-driven</FONT> -<BR><FONT FACE="Arial,Helvetica"> programming is -a big thing in ACE, you should get used to it. If the</FONT> -<BR><FONT FACE="Arial,Helvetica"> signal handler -catches something, the finished flag will be set and we'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> exit. Conveniently -enough, handle_events() is also interrupted by signals</FONT> -<BR><FONT FACE="Arial,Helvetica"> and will exit -back to the while() loop. (If you want your event loop to</FONT> -<BR><FONT FACE="Arial,Helvetica"> not be interrupted -by signals, checkout the <i>restart</i> flag on the</FONT> -<BR><FONT FACE="Arial,Helvetica"> open() method -of ACE_Reactor if you're interested.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> while (!finished)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -reactor.handle_events ();</FONT> - -<P><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting -down server daemon\n"));</FONT> -<BR><FONT FACE="Arial,Helvetica"> </FONT> -<BR><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Hmmm... No change there. Maybe I should leave out comments -on the stuff I don't change. Let's take a lookt at client_acceptor.h. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page03.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/007/page03.html b/docs/tutorials/007/page03.html deleted file mode 100644 index 694ed2505cc..00000000000 --- a/docs/tutorials/007/page03.html +++ /dev/null @@ -1,263 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 007</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Let's see what things we've had to add to <A HREF="client_acceptor.h">client_acceptor.h</A>. - -<P> -<HR WIDTH="100%"> -<BR><FONT FACE="Arial,Helvetica">// $Id: client_acceptor.h,v 1.1 1998/08/30 -16:04:11 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#ifndef CLIENT_ACCEPTOR_H</FONT> -<BR><FONT FACE="Arial,Helvetica">#define CLIENT_ACCEPTOR_H</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The ACE_Acceptor<> template -lives in the ace/Acceptor.h header file. You'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> find a very consitent naming -convention between the ACE objects and the</FONT> -<BR><FONT FACE="Arial,Helvetica"> headers where they can be -found. In general, the ACE object ACE_Foobar will</FONT> -<BR><FONT FACE="Arial,Helvetica"> be found in ace/Foobar.h.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "ace/Acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we want to work with -sockets, we'll need a SOCK_Acceptor to allow the</FONT> -<BR><FONT FACE="Arial,Helvetica"> clients to connect to us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "ace/SOCK_Acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The Client_Handler object -we develop will be used to handle clients once</FONT> -<BR><FONT FACE="Arial,Helvetica"> they're connected. -The ACE_Acceptor<> template's first parameter requires</FONT> -<BR><FONT FACE="Arial,Helvetica"> such an object. In -some cases, you can get by with just a forward</FONT> -<BR><FONT FACE="Arial,Helvetica"> declaration on the class, -in others you have to have the whole thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Parameterize the ACE_Acceptor<> -such that it will listen for socket</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection attempts and create -Client_Handler objects when they happen. In</FONT> -<BR><FONT FACE="Arial,Helvetica"> Tutorial 001, we wrote the -basic acceptor logic on our own before we</FONT> -<BR><FONT FACE="Arial,Helvetica"> realized that ACE_Acceptor<> -was available. You'll get spoiled using the</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE templates because they -take away a lot of the tedious details!</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">typedef ACE_Acceptor < Client_Handler, -ACE_SOCK_ACCEPTOR > Client_Acceptor_Base;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "thread_pool.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This time we've added quite -a bit more to our acceptor. In addition to</FONT> -<BR><FONT FACE="Arial,Helvetica"> providing a choice of concurrency -strategies, we also maintain a Thread_Pool</FONT> -<BR><FONT FACE="Arial,Helvetica"> object in case that strategy -is chosen. The object still isn't very complex</FONT> -<BR><FONT FACE="Arial,Helvetica"> but it's come a long way -from the simple typedef we had in Tutorial 5.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Why keep the thread pool as -a member? If we go back to the inetd concept</FONT> -<BR><FONT FACE="Arial,Helvetica"> you'll recall that we need -several acceptors to make that work. We may have</FONT> -<BR><FONT FACE="Arial,Helvetica"> a situation in which our -different client types requre different resources.</FONT> -<BR><FONT FACE="Arial,Helvetica"> That is, we may need a large -thread pool for some client types and a smaller</FONT> -<BR><FONT FACE="Arial,Helvetica"> one for others. We -could share a pool but then the client types may have</FONT> -<BR><FONT FACE="Arial,Helvetica"> undesirable impact on one -another.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Just in case you do want to -share a single thread pool, there is a constructor</FONT> -<BR><FONT FACE="Arial,Helvetica"> below that will let you do -that.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Client_Acceptor : public Client_Acceptor_Base</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">public:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -typedef Client_Acceptor_Base inherited;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Now that we have more than two strategies, we need more than a boolean</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to tell us what we're using. A set of enums is a good choice because</FONT> -<BR><FONT FACE="Arial,Helvetica"> -it allows us to use named values. Another option would be a set of</FONT> -<BR><FONT FACE="Arial,Helvetica"> -static const integers.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -enum concurrency_t</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -single_threaded_,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread_per_connection_,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread_pool_</FONT> -<BR><FONT FACE="Arial,Helvetica"> -};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -The default constructor allows the programmer to choose the concurrency</FONT> -<BR><FONT FACE="Arial,Helvetica"> -strategy. Since we want to focus on thread-pool, that's what we'll -use</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if nothing is specified.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Client_Acceptor( int _concurrency = thread_pool_ );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Another option is to construct the object with an existing thread pool.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -The concurrency strategy is pretty obvious at that point.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Client_Acceptor( Thread_Pool & _thread_pool );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Our destructor will take care of shutting down the thread-pool</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if applicable.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -~Client_Acceptor( void );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Open ourselves and register with the given reactor. The thread pool -size</FONT> -<BR><FONT FACE="Arial,Helvetica"> -can be specified here if you want to use that concurrency strategy.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int open( const ACE_INET_Addr & _addr, ACE_Reactor * _reactor,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int _pool_size = Thread_Pool::default_pool_size_ );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Close ourselves and our thread pool if applicable</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int close(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -What is our concurrency strategy?</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int concurrency(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ return this->concurrency_; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Give back a pointer to our thread pool. Our Client_Handler objects</FONT> -<BR><FONT FACE="Arial,Helvetica"> -will need this so that their handle_input() methods can put themselves</FONT> -<BR><FONT FACE="Arial,Helvetica"> -into the pool. Another alternative would be a globally accessible</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread pool. ACE_Singleton<> is a way to achieve that.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Thread_Pool * thread_pool(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ return & this->the_thread_pool_; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Since we can be constructed with a Thread_Pool reference, there are times</FONT> -<BR><FONT FACE="Arial,Helvetica"> -when we need to know if the thread pool we're using is ours or if we're</FONT> -<BR><FONT FACE="Arial,Helvetica"> -just borrowing it from somebody else.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int thread_pool_is_private(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ return &the_thread_pool_ == &private_thread_pool_; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int concurrency_;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -Thread_Pool private_thread_pool_;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -Thread_Pool & the_thread_pool_;</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_ACCEPTOR_H</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P> -<HR WIDTH="100%"> - -<P>Well, except for the new Thread_Pool member variable, most of the changes -are informational. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/007/page04.html b/docs/tutorials/007/page04.html deleted file mode 100644 index c74bcdf7dae..00000000000 --- a/docs/tutorials/007/page04.html +++ /dev/null @@ -1,133 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 007</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Something new this time is <A HREF="client_acceptor.cpp">client_acceptor.cpp</A>. -I finally had enough code to move it out of the header. - -<P> -<HR WIDTH="100%"> -<BR><FONT FACE="Arial,Helvetica">// $Id: client_acceptor.cpp,v 1.1 1998/08/30 -16:04:11 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Construct ourselves with -the chosen concurrency strategy. Notice that we also</FONT> -<BR><FONT FACE="Arial,Helvetica"> set our Thread_Pool reference -to our private instance.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::Client_Acceptor( int -_concurrency )</FONT> -<BR><FONT FACE="Arial,Helvetica"> : concurrency_(_concurrency)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ,the_thread_pool_(private_thread_pool_)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Construct ourselves with -a reference to somebody else' Thread_Pool. Obvioulsy</FONT> -<BR><FONT FACE="Arial,Helvetica"> our concurrency strategy -is "thread_pool_" at this point.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::Client_Acceptor( Thread_Pool -& _thread_pool )</FONT> -<BR><FONT FACE="Arial,Helvetica"> : concurrency_(thread_pool_)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ,the_thread_pool_(_thread_pool)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When we're destructed, we -may need to cleanup after ourselves. If we're running</FONT> -<BR><FONT FACE="Arial,Helvetica"> with a thread pool that we -own, it is up to us to close it down.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Acceptor::~Client_Acceptor( void -)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( this->concurrency() == thread_pool_ && thread_pool_is_private() -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread_pool()->close();</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Similar to the destructor -(and close() below) it is necessary for us to open the</FONT> -<BR><FONT FACE="Arial,Helvetica"> thread pool in some circumstances.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Notice how we delegate most -of the open() work to the open() method of our baseclass.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Acceptor::open( const ACE_INET_Addr -& _addr, ACE_Reactor * _reactor, int _pool_size )</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( this->concurrency() == thread_pool_ && thread_pool_is_private() -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread_pool()->open(_pool_size);</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -return inherited::open(_addr,_reactor);</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Here again we find that we -have to manage the thread pool. Like open() we also delegate</FONT> -<BR><FONT FACE="Arial,Helvetica"> the other work to our baseclass.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Acceptor::close(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( this->concurrency() == thread_pool_ && thread_pool_is_private() -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread_pool()->close();</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -return inherited::close();</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> -<BR><FONT FACE="Arial,Helvetica"></FONT> <FONT FACE="Arial,Helvetica"></FONT> - -<P> -<HR WIDTH="100%"> - -<P>Nothing really surprising here. Most of it just manages the Thread_Pool. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/007/page05.html b/docs/tutorials/007/page05.html deleted file mode 100644 index a5ad7a8d62e..00000000000 --- a/docs/tutorials/007/page05.html +++ /dev/null @@ -1,294 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 007</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>As you might expect, <A HREF="client_handler.h">client_handler.h</A> -is next. - -<P> -<HR WIDTH="100%"> -<BR> -<BR><FONT FACE="Arial,Helvetica">// $Id: client_handler.h,v 1.1 1998/08/30 -23:47:14 schmidt Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#ifndef CLIENT_HANDLER_H</FONT> -<BR><FONT FACE="Arial,Helvetica">#define CLIENT_HANDLER_H</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our client handler must exist -somewhere in the ACE_Event_Handler object</FONT> -<BR><FONT FACE="Arial,Helvetica"> hierarchy. This is -a requirement of the ACE_Reactor because it maintains</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_Event_Handler pointers -for each registered event handler. You could</FONT> -<BR><FONT FACE="Arial,Helvetica"> derive our Client_Handler -directly from ACE_Event_Handler but you still have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to have an ACE_SOCK_Stream -for the actually connection. With a direct</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler, -you'll have to contain and maintain an</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_SOCK_Stream instance -yourself. With ACE_Svc_Handler (which is a</FONT> -<BR><FONT FACE="Arial,Helvetica"> derivative of ACE_Event_Handler) -some of those details are handled for you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "ace/Svc_Handler.h"</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "ace/SOCK_Stream.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">class Client_Acceptor;</FONT> -<BR><FONT FACE="Arial,Helvetica">class Thread_Pool;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Another feature of ACE_Svc_Handler -is it's ability to present the ACE_Task<></FONT> -<BR><FONT FACE="Arial,Helvetica"> interface as well. -That's what the ACE_NULL_SYNCH parameter below is all</FONT> -<BR><FONT FACE="Arial,Helvetica"> about. That's beyond -our scope here but we'll come back to it in the next</FONT> -<BR><FONT FACE="Arial,Helvetica"> tutorial when we start looking -at concurrency options.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Client_Handler : public ACE_Svc_Handler -< ACE_SOCK_STREAM, ACE_NULL_SYNCH ></FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">public:</FONT> -<BR><FONT FACE="Arial,Helvetica"> typedef ACE_Svc_Handler < ACE_SOCK_STREAM, -ACE_NULL_SYNCH > inherited;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> // Constructor...</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The destroy() -method is our preferred method of destruction. We could</FONT> -<BR><FONT FACE="Arial,Helvetica"> have overloaded -the delete operator but that is neither easy nor</FONT> -<BR><FONT FACE="Arial,Helvetica"> intuitive (at -least to me). Instead, we provide a new method of</FONT> -<BR><FONT FACE="Arial,Helvetica"> destruction and -we make our destructor protected so that only ourselves,</FONT> -<BR><FONT FACE="Arial,Helvetica"> our derivatives -and our friends can delete us. It's a nice</FONT> -<BR><FONT FACE="Arial,Helvetica"> compromise.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> void destroy (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Most ACE objects -have an open() method. That's how you make them ready</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do work. -ACE_Event_Handler has a virtual open() method which allows us</FONT> -<BR><FONT FACE="Arial,Helvetica"> to create this -overrride. ACE_Acceptor<> will invoke this method after</FONT> -<BR><FONT FACE="Arial,Helvetica"> creating a new -Client_Handler when a client connects. Notice that the</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter to -open() is a void*. It just so happens that the pointer</FONT> -<BR><FONT FACE="Arial,Helvetica"> points to the -acceptor which created us. You would like for the parameter</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be an ACE_Acceptor<>* -but since ACE_Event_Handler is generic, that</FONT> -<BR><FONT FACE="Arial,Helvetica"> would tie it -too closely to the ACE_Acceptor<> set of objects. In our</FONT> -<BR><FONT FACE="Arial,Helvetica"> definition of -open() you'll see how we get around that.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int open (void *_acceptor);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When an ACE_Task<> -object falls out of the svc() method, the framework</FONT> -<BR><FONT FACE="Arial,Helvetica"> will call the -close() method. That's where we want to cleanup ourselves</FONT> -<BR><FONT FACE="Arial,Helvetica"> if we're running -in either thread-per-connection or thread-pool mode.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int close(u_long flags = 0);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When there is -activity on a registered handler, the handle_input() method</FONT> -<BR><FONT FACE="Arial,Helvetica"> of the handler -will be invoked. If that method returns an error code (eg</FONT> -<BR><FONT FACE="Arial,Helvetica"> -- -1) then the -reactor will invoke handle_close() to allow the object to</FONT> -<BR><FONT FACE="Arial,Helvetica"> clean itself -up. Since an event handler can be registered for more than</FONT> -<BR><FONT FACE="Arial,Helvetica"> one type of callback, -the callback mask is provided to inform</FONT> -<BR><FONT FACE="Arial,Helvetica"> handle_close() -exactly which method failed. That way, you don't have to</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintain state -information between your handle_* method calls. The _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter is -explained below...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int handle_close (ACE_HANDLE _handle, -ACE_Reactor_Mask _mask);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When we register -with the reactor, we're going to tell it that we want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> be notified of -READ events. When the reactor sees that there is read</FONT> -<BR><FONT FACE="Arial,Helvetica"> activity for -us, our handle_input() will be invoked. The _handleg</FONT> -<BR><FONT FACE="Arial,Helvetica"> provided is the -handle (file descriptor in Unix) of the actual connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> causing the activity. -Since we're derived from ACE_Svc_Handler<> and it</FONT> -<BR><FONT FACE="Arial,Helvetica"> maintains it's -own peer (ACE_SOCK_Stream) object, this is redundant for</FONT> -<BR><FONT FACE="Arial,Helvetica"> us. However, -if we had been derived directly from ACE_Event_Handler, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> may have chosen -not to contain the peer. In that case, the _handleg</FONT> -<BR><FONT FACE="Arial,Helvetica"> would be important -to us for reading the client's data.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int handle_input (ACE_HANDLE _handle);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If the Client_Acceptor -which created us has chosen a thread-per-connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> strategy then -our open() method will activate us into a dedicate thread.</FONT> -<BR><FONT FACE="Arial,Helvetica"> The svc() method -will then execute in that thread performing some of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> functions we -used to leave up to the reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int svc(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This has nothing -at all to do with ACE. I've added this here as a worker</FONT> -<BR><FONT FACE="Arial,Helvetica"> function which -I will call from handle_input(). That allows me to</FONT> -<BR><FONT FACE="Arial,Helvetica"> introduce concurrencly -in later tutorials with a no changes to the worker</FONT> -<BR><FONT FACE="Arial,Helvetica"> function. -You can think of process() as application-level code and</FONT> -<BR><FONT FACE="Arial,Helvetica"> everything elase -as application-framework code.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int process (char *_rdbuf, int -_rdbuf_len);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We don't really -do anything in our destructor but we've declared it to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> protected to -prevent casual deletion of this object. As I said above, I</FONT> -<BR><FONT FACE="Arial,Helvetica"> really would -prefer that everyone goes through the destroy() method to get</FONT> -<BR><FONT FACE="Arial,Helvetica"> rid of us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ~Client_Handler (void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When we -get to the definition of Client_Handler we'll see that there are</FONT> -<BR><FONT FACE="Arial,Helvetica"> -several places where we go back to the Client_Acceptor for information.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -It is generally a good idea to do that through an accesor rather than</FONT> -<BR><FONT FACE="Arial,Helvetica"> -using the member variable directly.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor * client_acceptor( -void )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ return this->client_acceptor_; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> And since -you shouldn't access a member variable directly, neither should you</FONT> -<BR><FONT FACE="Arial,Helvetica"> -set (mutate) it. Although it might seem silly to do it this way, -you'll thank</FONT> -<BR><FONT FACE="Arial,Helvetica"> -yourself for it later.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> void client_acceptor( Client_Acceptor -* _client_acceptor )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{ this->client_acceptor_ = _client_acceptor; }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The concurrency() -accessor tells us the current concurrency strategy. It actually</FONT> -<BR><FONT FACE="Arial,Helvetica"> -queries the Client_Acceptor for it but by having the accessor in place, -we could</FONT> -<BR><FONT FACE="Arial,Helvetica"> -change our implementation without affecting everything that needs to know.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> int concurrency(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Likewise -for access to the Thread_Pool that we belong to.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Thread_Pool * thread_pool(void);</FONT> -<BR><FONT FACE="Arial,Helvetica"></FONT> <FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Client_Acceptor * client_acceptor_;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> For some -reason I didn't create accessor/mutator methods for this. So much -for</FONT> -<BR><FONT FACE="Arial,Helvetica"> -consistency....</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -This variable is used to remember the thread in which we were created: -the "creator"</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread in other words. handle_input() needs to know if it is operating -in the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -main reactor thread (which is the one that created us) or if it is operating -in</FONT> -<BR><FONT FACE="Arial,Helvetica"> -one of the thread pool threads. More on this when we get to handle_input().</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_thread_t -creator_;</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // CLIENT_HANDLER_H</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Still, we're just not seeing a lot of changes due to intruduction of -the thread pool. That's a good thing! You don't want to go turning -your application upside down just because you changed thread models. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page06.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/007/page06.html b/docs/tutorials/007/page06.html deleted file mode 100644 index f4e14834b49..00000000000 --- a/docs/tutorials/007/page06.html +++ /dev/null @@ -1,365 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 007</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P><A HREF="client_handler.cpp">client_handler.cpp</A> -shows some of the changes due to the thread-pool. Just a few -though. - -<P> -<HR WIDTH="100%"> -<BR> -<BR><FONT FACE="Arial,Helvetica">// $Id: client_handler.cpp,v 1.1 1998/08/30 -23:47:14 schmidt Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since this is the third time -we've seen most of this, I'm going to strip out almost</FONT> -<BR><FONT FACE="Arial,Helvetica"> all of the comments that -you've already seen. That way, you can concentrate on the</FONT> -<BR><FONT FACE="Arial,Helvetica"> new items.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We're going to be registering -and unregistering a couple of times. To make sure that</FONT> -<BR><FONT FACE="Arial,Helvetica"> we use the same flags every -time, I've created these handy macros.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#define REGISTER_MASK -ACE_Event_Handler::READ_MASK</FONT> -<BR><FONT FACE="Arial,Helvetica">#define REMOVE_MASK -(ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL)</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our constructor still doesn't -really do anything. We simply initialize the acceptor</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer to "null" and get -our current thread id. The static self() method of ACE_Thread</FONT> -<BR><FONT FACE="Arial,Helvetica"> will return you a thread -id native to your platform.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Handler::Client_Handler (void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> : client_acceptor_(0)</FONT> -<BR><FONT FACE="Arial,Helvetica"> ,creator_(ACE_Thread::self())</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">Client_Handler::~Client_Handler (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Query our acceptor for the -concurrency strategy. Notice that we don't bother</FONT> -<BR><FONT FACE="Arial,Helvetica"> to check that our acceptor -pointer is valid. That is proably a bad idea...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::concurrency(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return this->client_acceptor()->concurrency();</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> And here we ask the acceptor -about the thread pool.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Thread_Pool * Client_Handler::thread_pool(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return this->client_acceptor()->thread_pool();</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The destroy() method hasn't -changed since we wrote it back in Tutorial 5.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">void Client_Handler::destroy (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->peer ().close ();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> this->reactor ()->remove_handler -(this, REMOVE_MASK );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> delete this;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Back to our open() method. -This is straight out of Tutorial 6. There's</FONT> -<BR><FONT FACE="Arial,Helvetica"> nothing additional here for -the thread-pool implementation.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::open (void *_acceptor)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> client_acceptor( (Client_Acceptor -*) _acceptor );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> if( concurrency() == Client_Acceptor::thread_per_connection_ -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return this->activate();</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> this->reactor (client_acceptor()->reactor -());</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> ACE_INET_Addr addr;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> if (this->peer ().get_remote_addr -(addr) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return --1;</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> if (this->reactor ()->register_handler -(this, REGISTER_MASK) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected -with %s\n", addr.get_host_name ()));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As mentioned in the header, -the typical way to close an object in a threaded</FONT> -<BR><FONT FACE="Arial,Helvetica"> context is to invoke it's -close() method. Since we already have a handle_close()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method built to cleanup after -us, we'll just forward the request on to that</FONT> -<BR><FONT FACE="Arial,Helvetica"> object.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::close(u_long flags)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this->handle_close(ACE_INVALID_HANDLE,0);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -After we've taken care of ourselves, call the baseclass method</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to do any other necessary cleanup.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return inherited::close();</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In the open() method, we -registered with the reactor and requested to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> notified when there is data -to be read. When the reactor sees that activity</FONT> -<BR><FONT FACE="Arial,Helvetica"> it will invoke this handle_input() -method on us. As I mentioned, the _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter isn't useful to -us but it narrows the list of methods the reactor</FONT> -<BR><FONT FACE="Arial,Helvetica"> has to worry about and the -list of possible virtual functions we would have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to override.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> You've read that much before... -Now we have to do some extra stuff in case</FONT> -<BR><FONT FACE="Arial,Helvetica"> we're using the thread-pool -implementation. If we're called by our creator</FONT> -<BR><FONT FACE="Arial,Helvetica"> thread then we must be in -the reactor. In that case, we arrange to be put</FONT> -<BR><FONT FACE="Arial,Helvetica"> into the thread pool. -If we're not in the creator thread then we must be</FONT> -<BR><FONT FACE="Arial,Helvetica"> in the thread pool and we -can do some work.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::handle_input (ACE_HANDLE -_handle)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_handle);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Check our strategy. -If we're using the thread pool and we're in the creation</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread then we know we were called by the reactor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( concurrency() == Client_Acceptor::thread_pool_ -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( ACE_Thread::self() == creator_ )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Remove ourselves from the reactor and ask to be put into the thread pool's</FONT> -<BR><FONT FACE="Arial,Helvetica"> -queue of work. (You should be able to use suspend_handler() but I've -had</FONT> -<BR><FONT FACE="Arial,Helvetica"> -problems with that.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this->reactor()->remove_handler( this, REMOVE_MASK );</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return this->thread_pool()->enqueue(this);</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Any strategy -other than thread-per-connection will eventually get here. If we're -in the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -single-threaded implementation or the thread-pool, we still have to pass -this way.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, 0, sizeof (buf));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Invoke the process() -method to do the work but save it's return value instead</FONT> -<BR><FONT FACE="Arial,Helvetica"> -of returning it immediately.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> int rval = this->process(buf,sizeof(buf));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Now, we look -again to see if we're in the thread-pool implementation. If so then -we</FONT> -<BR><FONT FACE="Arial,Helvetica"> -need to re-register ourselves with the reactor so that we can get more -work when it</FONT> -<BR><FONT FACE="Arial,Helvetica"> -is available. (If suspend_handler() worked then we would use resume_handler() -here.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( concurrency() == Client_Acceptor::thread_pool_ -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( rval != -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this->reactor()->register_handler( this, REGISTER_MASK );</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Return the result -of process()</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> return(rval);</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">int Client_Handler::handle_close (ACE_HANDLE -_handle, ACE_Reactor_Mask _mask)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_handle);</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_mask);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> this->destroy ();</FONT> -<BR><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Remember that when we leave -our svc() method, the framework will take care</FONT> -<BR><FONT FACE="Arial,Helvetica"> of calling our close() method -so that we can cleanup after ourselves.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::svc(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, 0, sizeof (buf));</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> while( 1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( this->process(buf,sizeof(buf)) -== -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return(-1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> return(0);</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Once again, we see that the -application-level logic has not been at all affected</FONT> -<BR><FONT FACE="Arial,Helvetica"> by our choice of threading -models. Of course, I'm not sharing data between threads</FONT> -<BR><FONT FACE="Arial,Helvetica"> or anything. We'll -leave locking issues for a later tutorial.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::process (char *_rdbuf, -int _rdbuf_len)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> switch (this->peer ().recv (_rdbuf, -_rdbuf_len))</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> case -1:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> case 0:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), --1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> default:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG -((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf));</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Ok, now we've gone and changed handle_input() so that it knows when -to do work and when to enqueue itself. Beyond that, we're still about -the same. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page07.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/007/page07.html b/docs/tutorials/007/page07.html deleted file mode 100644 index 4c6905ebf33..00000000000 --- a/docs/tutorials/007/page07.html +++ /dev/null @@ -1,197 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 007</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Two new files this time. The first is <A HREF="thread_pool.h">thread_pool.h</A> -where we declare our Thread_Pool object. This is responsible for -abstracting away the thread pool implementation details and allowing us -to make so few changes to the rest of the code. - -<P> -<HR WIDTH="100%"><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">// $Id: thread_pool.h,v 1.1 1998/08/30 -16:04:12 jcej Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#ifndef THREAD_POOL_H</FONT> -<BR><FONT FACE="Arial,Helvetica">#define THREAD_POOL_H</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In order to implement a thread -pool, we have to have an object that can create</FONT> -<BR><FONT FACE="Arial,Helvetica"> a thread. The ACE_Task<> -is the basis for doing just such a thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "ace/Task.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We need a forward reference -for ACE_Event_Handler so that our enqueue() method</FONT> -<BR><FONT FACE="Arial,Helvetica"> can accept a pointer to one.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class ACE_Event_Handler;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Although we modified the -rest of our program to make use of the thread pool</FONT> -<BR><FONT FACE="Arial,Helvetica"> implementation, if you look -closely you'll see that the changes were rather</FONT> -<BR><FONT FACE="Arial,Helvetica"> minor. The "ACE way" -is generally to create a helper object that abstracts</FONT> -<BR><FONT FACE="Arial,Helvetica"> away the details not relevant -to your application. That's what I'm trying</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do here by creating the -Thread_Pool object.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Thread_Pool : public ACE_Task<ACE_MT_SYNCH></FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">public:</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Provide an enumeration for the default pool size. By doing this, -other objects</FONT> -<BR><FONT FACE="Arial,Helvetica"> -can use the value when they want a default.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -enum size_t</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -default_pool_size_ = 5</FONT> -<BR><FONT FACE="Arial,Helvetica"> -};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -// Basic constructor</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Thread_Pool(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Opening the thread pool causes one or more threads to be activated. -When activated,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -they all execute the svc() method declared below.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int open( int _pool_size = default_pool_size_ );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -When you're done wit the thread pool, you have to have some way to shut -it down.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -This is what close() is for.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int close(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -To use the thread pool, you have to put some unit of work into it. -Since we're</FONT> -<BR><FONT FACE="Arial,Helvetica"> -dealing with event handlers (or at least their derivatives), I've chosen -to provide</FONT> -<BR><FONT FACE="Arial,Helvetica"> -an enqueue() method that takes a pointer to an ACE_Event_Handler. -The handler's</FONT> -<BR><FONT FACE="Arial,Helvetica"> -handle_input() method will be called, so your object has to know when it -is being</FONT> -<BR><FONT FACE="Arial,Helvetica"> -called by the thread pool.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int enqueue( ACE_Event_Handler * _handler );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Our svc() method will dequeue the enqueued event handler objects and invoke -the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -handle_input() method on each. Since we're likely running in more -than one thread,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -idle threads can take work from the queue while other threads are busy -executing</FONT> -<BR><FONT FACE="Arial,Helvetica"> -handle_input() on some object.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int svc(void);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Another handy ACE template is ACE_Atomic_Op<>. When parameterized, -this allows</FONT> -<BR><FONT FACE="Arial,Helvetica"> -is to have a thread-safe counting object. The typical arithmetic -operators are</FONT> -<BR><FONT FACE="Arial,Helvetica"> -all internally thread-safe so that you can share it across threads without -worrying</FONT> -<BR><FONT FACE="Arial,Helvetica"> -about any contention issues.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -typedef ACE_Atomic_Op<ACE_Mutex,int> counter_t;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -We use the atomic op to keep a count of the number of threads in which -our svc()</FONT> -<BR><FONT FACE="Arial,Helvetica"> -method is running. This is particularly important when we want to -close() it down!</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -counter_t active_threads_;</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#endif // THREAD_POOL_H</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P> -<HR WIDTH="100%"> - -<P>Well, that doesn't look too complex. What about the implementation? - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page08.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/007/page08.html b/docs/tutorials/007/page08.html deleted file mode 100644 index 094804e743d..00000000000 --- a/docs/tutorials/007/page08.html +++ /dev/null @@ -1,537 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 007</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Finally, <A HREF="thread_pool.cpp">thread_pool.cpp</A> -where we have the Thread_Pool object implementation. - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: thread_pool.cpp,v 1.1 1998/08/30 -23:47:15 schmidt Exp $</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">#include "thread_pool.h"</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We need this header so that -we can invoke handle_input() on the objects we dequeue.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "ace/Event_Handler.h"</FONT> -<BR><FONT FACE="Arial,Helvetica"></FONT> <FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> All we do here is initialize -our active thread counter.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Thread_Pool::Thread_Pool(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> : active_threads_(0)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our open() method is a thin -disguise around the ACE_Task<> activate() method. By</FONT> -<BR><FONT FACE="Arial,Helvetica"> hiding activate() in this -way, the users of Thread_Pool don't have to worry about</FONT> -<BR><FONT FACE="Arial,Helvetica"> the thread configuration -flags.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::open( int _pool_size -)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> return this->activate(THR_NEW_LWP|THR_DETACHED,_pool_size);</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Closing the thread pool can -be a tricky exercise. I've decided to take an easy approach</FONT> -<BR><FONT FACE="Arial,Helvetica"> and simply enqueue a secret -message for each thread we have active.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::close(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Find out how many threads are currently active</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -int counter = active_threads_.value();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -For each one of the active threads, enqueue a "null" event handler. -Below, we'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> -teach our svc() method that "null" means "shutdown".</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -while( counter-- )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this->enqueue( 0 );</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -As each svc() method exits, it will decrement the active thread counter. -We just wait</FONT> -<BR><FONT FACE="Arial,Helvetica"> -here for it to reach zero. Since we don't know how long it will take, -we sleep for</FONT> -<BR><FONT FACE="Arial,Helvetica"> -a quarter-second or so between tries.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -while( active_threads_.value() )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_OS::sleep( ACE_Time_Value(0.25) );</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -return(0);</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> When an object wants to do -work in the pool, it should call the enqueue() method.</FONT> -<BR><FONT FACE="Arial,Helvetica"> We introduce the ACE_Message_Block -here but, unfortunately, we seriously missuse it.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::enqueue( ACE_Event_Handler -* _handler )</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -An ACE_Message_Block is a chunk of data. You put them into an ACE_Message_Queue.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Task<> has an ACE_Message_Queue built in. In fact, the parameter -to ACE_Task<></FONT> -<BR><FONT FACE="Arial,Helvetica"> -is passed directly to ACE_Message_Queue. If you look back at our -header file you'll</FONT> -<BR><FONT FACE="Arial,Helvetica"> -see that we used ACE_MT_SYNCH as the parameter indicating that we want -MultiThread</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Synch safety. This allows us to safely put ACE_Message_Block objects -into the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -message queue in one thread and take them out in another.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -An ACE_Message_Block wants to have char* data. We don't have that. -We could</FONT> -<BR><FONT FACE="Arial,Helvetica"> -cast our ACE_Event_Handler* directly to a char* but I wanted to be more -explicit.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Since casting pointers around is a dangerous thing, I've gone out of my -way here</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to be very clear about what we're doing.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -First: Cast the handler pointer to a void pointer. You can't -do any useful work</FONT> -<BR><FONT FACE="Arial,Helvetica"> -on a void pointer, so this is a clear message that we're making the</FONT> -<BR><FONT FACE="Arial,Helvetica"> -pointer unusable.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -Next: Cast the void pointer to a char pointer that the ACE_Message_Block -will accept.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -void * v_data = (void*)_handler;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -char * c_data = (char*)v_data;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Construct a new ACE_Message_Block. For efficiency, you might want -to preallocate a</FONT> -<BR><FONT FACE="Arial,Helvetica"> -stack of these and reuse them. For simplicity, I'll just create what -I need as I need it.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Message_Block * mb = new ACE_Message_Block( c_data );</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Our putq() method is a wrapper around one of the enqueue methods of the -ACE_Message_Queue</FONT> -<BR><FONT FACE="Arial,Helvetica"> -that we own. Like all good methods, it returns -1 if it fails for -some reason.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( this->putq(mb) == -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Another trait of the ACE_Message_Block objects is that they are reference -counted.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Since they're designed to be passed around between various objects in several -threads</FONT> -<BR><FONT FACE="Arial,Helvetica"> -we can't just delete them whenever we feel like it. The release() -method is similar</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to the destroy() method we've used elsewhere. It watches the reference -count and will</FONT> -<BR><FONT FACE="Arial,Helvetica"> -delete the object when possible.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -mb->release();</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return(-1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -return(0);</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The "guard" concept is very -powerful and used throughout multi-threaded applications.</FONT> -<BR><FONT FACE="Arial,Helvetica"> A guard normally does some -operation on an object at construction and the "opposite"</FONT> -<BR><FONT FACE="Arial,Helvetica"> operation at destruction. -For instance, when you guard a mutex (lock) object, the guard</FONT> -<BR><FONT FACE="Arial,Helvetica"> will acquire the lock on -construction and release it on destruction. In this way, your</FONT> -<BR><FONT FACE="Arial,Helvetica"> method can simply let the -guard go out of scope and know that the lock is released.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> Guards aren't only useful -for locks however. In this application I've created two guard</FONT> -<BR><FONT FACE="Arial,Helvetica"> objects for quite a different -purpose.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The Counter_Guard is constructed -with a reference to the thread pool's active thread</FONT> -<BR><FONT FACE="Arial,Helvetica"> counter. The guard -increments the counter when it is created and decrements it at</FONT> -<BR><FONT FACE="Arial,Helvetica"> destruction. By creating -one of these in svc(), I know that the counter will be decremented</FONT> -<BR><FONT FACE="Arial,Helvetica"> no matter how or where svc() -returns.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Counter_Guard</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">public:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Counter_Guard( Thread_Pool::counter_t & _counter )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -: counter_(_counter)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -++counter_;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -~Counter_Guard(void)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> ---counter_;</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Thread_Pool::counter_t & counter_;</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> My Message_Block_Guard is -also a little non-traditional. It doesn't do anything in the</FONT> -<BR><FONT FACE="Arial,Helvetica"> constructor but it's destructor -ensures that the message block's release() method is called.</FONT> -<BR><FONT FACE="Arial,Helvetica"> This is a cheap way to prevent -a memory leak if I need an additional exit point in svc().</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">class Message_Block_Guard</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">public:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Message_Block_Guard( ACE_Message_Block * & _mb )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -: mb_(_mb)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -~Message_Block_Guard( void )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -mb_->release();</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">protected:</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Message_Block * & mb_;</FONT> -<BR><FONT FACE="Arial,Helvetica">};</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Now we come to the svc() -method. As I said, this is being executed in each thread of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> Thread_Pool. Here, -we pull messages off of our built-in ACE_Message_Queue and cause them</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do work.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Thread_Pool::svc(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -The getq() method takes a reference to a pointer. So... we need a -pointer to give it</FONT> -<BR><FONT FACE="Arial,Helvetica"> -a reference to.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Message_Block * mb;</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Create the guard for our active thread counter object. No matter -where we choose to</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return() from svc(), we no know that the counter will be decremented.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Counter_Guard counter_guard(active_threads_);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Get messages from the queue until we have a failure. There's no real -good reason</FONT> -<BR><FONT FACE="Arial,Helvetica"> -for failure so if it happens, we leave immediately.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -while( this->getq(mb) != -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -A successful getq() will cause "mb" to point to a valid refernce-counted</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Message_Block. We use our guard object here so that we're sure -to call</FONT> -<BR><FONT FACE="Arial,Helvetica"> -the release() method of that message block and reduce it's reference count.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Once the count reaches zero, it will be deleted.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Message_Block_Guard message_block_guard(mb);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -As noted before, the ACE_Message_Block stores it's data as a char*. -We pull that</FONT> -<BR><FONT FACE="Arial,Helvetica"> -out here and later turn it into an ACE_Event_Handler*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -char * c_data = mb->base();</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -We've chosen to use a "null" value as an indication to leave. If -the data we got</FONT> -<BR><FONT FACE="Arial,Helvetica"> -from the queue is not null then we have some work to do.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( c_data )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Once again, we go to great lengths to emphasize the fact that we're casting -pointers</FONT> -<BR><FONT FACE="Arial,Helvetica"> -around in rather impolite ways. We could have cast the char* directly -to an</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Event_Handler* but then folks might think that's an OK thing to do.</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -(Note: The correct way to use an ACE_Message_Block is to write data -into it.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -What I should have done was create a message block big enough to hold an</FONT> -<BR><FONT FACE="Arial,Helvetica"> -event handler pointer and then written the pointer value into the block. -When</FONT> -<BR><FONT FACE="Arial,Helvetica"> -we got here, I would have to read that data back into a pointer. -While politically</FONT> -<BR><FONT FACE="Arial,Helvetica"> -correct, it is also a lot of work. If you're careful you can get -away with casting</FONT> -<BR><FONT FACE="Arial,Helvetica"> -pointers around.)</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -void * v_data = (void*)c_data;</FONT> -<BR><FONT FACE="Arial,Helvetica"> </FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Event_Handler * handler = (ACE_Event_Handler*)v_data;</FONT> -<BR><FONT FACE="Arial,Helvetica"> </FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Now that we finally have an event handler pointer, invoke it's handle_input() -method.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Since we don't know it's handle, we just give it a default. That's -OK because we</FONT> -<BR><FONT FACE="Arial,Helvetica"> -know that we're not using the handle in the method anyway.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -if( handler->handle_input(ACE_INVALID_HANDLE) == -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Tell the handler that it's time to go home. The "normal" method for -shutting</FONT> -<BR><FONT FACE="Arial,Helvetica"> -down a handler whose handler failed is to invoke handle_close(). -This will</FONT> -<BR><FONT FACE="Arial,Helvetica"> -take care of cleaning it up for us.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Notice how we use the handler's get_handle() method to populate it's "handle"</FONT> -<BR><FONT FACE="Arial,Helvetica"> -parameter. Convenient isn't it?</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -handler->handle_close(handler->get_handle(),0);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Also notice that we don't exit the svc() method here! The first time -I did</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this, I was exiting. After a few clients disconnect you have an empty</FONT> -<BR><FONT FACE="Arial,Helvetica"> -thread pool. Hard to do any more work after that...</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT> -<BR><FONT FACE="Arial,Helvetica"> -else</FONT> -<BR><FONT FACE="Arial,Helvetica"> -{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -If we get here, we were given a message block with "null" data. That -is our</FONT> -<BR><FONT FACE="Arial,Helvetica"> -signal to leave, so we return(0) to leave gracefully.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return(0); -// Ok, shutdown request</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -// message_block_guard goes out of scope here</FONT> -<BR><FONT FACE="Arial,Helvetica"> -// and releases the message_block instance.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -}</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -return(0);</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page09.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/007/page09.html b/docs/tutorials/007/page09.html deleted file mode 100644 index af87b79444c..00000000000 --- a/docs/tutorials/007/page09.html +++ /dev/null @@ -1,64 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 006</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 007</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-pool server</FONT></B></CENTER> - -<HR WIDTH="100%"> - -<P>That's it for Tutorial 7. As with Tutorial 6, we really didn't -have to change much to introduce a new threading strategy. Most of -the work was in creating the Thread_Pool object itself. Everything -else was just minor housekeeping. - -<P>There is a fourth common thread strategy: thread-per-request. -It's not one of my favorites, so I wasn't planning to go into it. -If you want to contribute a tutorial on that topic though, I'll be glad -to include it here. - -<P>For reference, here's the file list again: -<UL> -<LI> -<A HREF="Makefile">Makefile</A></LI> - -<LI> -<A HREF="client_acceptor.h">client_acceptor.h</A></LI> - -<LI> -<A HREF="client_acceptor.cpp">client_acceptor.cpp</A></LI> - -<LI> -<A HREF="client_handler.cpp">client_handler.cpp</A></LI> - -<LI> -<A HREF="client_handler.h">client_handler.h</A></LI> - -<LI> -<A HREF="server.cpp">server.cpp</A></LI> - -<LI> -<A HREF="thread_pool.h">thread_pool.h</A></LI> - -<LI> -<A HREF="thread_pool.cpp">thread_pool.cpp</A></LI> - -<LI> -<A HREF="fix.Makefile">fix.Makefile</A></LI> -</UL> - - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/007/server.cpp b/docs/tutorials/007/server.cpp deleted file mode 100644 index 55fb69c58ef..00000000000 --- a/docs/tutorials/007/server.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// $Id$ - -/* - We try to keep main() very simple. One of the ways we do that is to push - much of the complicated stuff into worker objects. In this case, we only - need to include the acceptor header in our main source file. We let it - worry about the "real work". - */ - -#include "client_acceptor.h" - -/* - As before, we create a simple signal handler that will set our finished - flag. There are, of course, more elegant ways to handle program shutdown - requests but that isn't really our focus right now, so we'll just do the - easiest thing. - */ - -static sig_atomic_t finished = 0; -extern "C" void handler (int) -{ - finished = 1; -} - -/* - A server has to listen for clients at a known TCP/IP port. The default ACE - port is 10002 (at least on my system) and that's good enough for what we - want to do here. Obviously, a more robust application would take a command - line parameter or read from a configuration file or do some other clever - thing. Just like the signal handler above, though, that's what we want to - focus on, so we're taking the easy way out. - */ - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -/* - Finally, we get to main. Some C++ compilers will complain loudly if your - function signature doesn't match the prototype. Even though we're not - going to use the parameters, we still have to specify them. - */ - -int main (int argc, char *argv[]) -{ -/* - In our earlier servers, we used a global pointer to get to the reactor. I've - never really liked that idea, so I've moved it into main() this time. When - we get to the Client_Handler object you'll see how we manage to get a - pointer back to this reactor. - */ - ACE_Reactor reactor; - - /* - The acceptor will take care of letting clients connect to us. It will - also arrange for a Client_Handler to be created for each new client. - Since we're only going to listen at one TCP/IP port, we only need one - acceptor. If we wanted, though, we could create several of these and - listen at several ports. (That's what we would do if we wanted to rewrite - inetd for instance.) - */ - Client_Acceptor peer_acceptor; - - /* - Create an ACE_INET_Addr that represents our endpoint of a connection. We - then open our acceptor object with that Addr. Doing so tells the acceptor - where to listen for connections. Servers generally listen at "well known" - addresses. If not, there must be some mechanism by which the client is - informed of the server's address. - - Note how ACE_ERROR_RETURN is used if we fail to open the acceptor. This - technique is used over and over again in our tutorials. - */ - if (peer_acceptor.open (ACE_INET_Addr (PORT), &reactor) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - - /* - Install our signal handler. You can actually register signal handlers - with the reactor. You might do that when the signal handler is - responsible for performing "real" work. Our simple flag-setter doesn't - justify deriving from ACE_Event_Handler and providing a callback function - though. - */ - ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - /* - Like ACE_ERROR_RETURN, the ACE_DEBUG macro gets used quite a bit. It's a - handy way to generate uniform debug output from your program. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server daemon\n")); - - /* - This will loop "forever" invoking the handle_events() method of our - reactor. handle_events() watches for activity on any registered handlers - and invokes their appropriate callbacks when necessary. Callback-driven - programming is a big thing in ACE, you should get used to it. If the - signal handler catches something, the finished flag will be set and we'll - exit. Conveniently enough, handle_events() is also interrupted by signals - and will exit back to the while() loop. (If you want your event loop to - not be interrupted by signals, checkout the <i>restart</i> flag on the - open() method of ACE_Reactor if you're interested.) - */ - while (!finished) - reactor.handle_events (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server daemon\n")); - - return 0; -} - -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -template class ACE_Guard<ACE_Mutex>; -template class ACE_Atomic_Op<ACE_Mutex, int>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#pragma instantiate ACE_Guard<ACE_Mutex> -#pragma instantiate ACE_Atomic_Op<ACE_Mutex, int> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ diff --git a/docs/tutorials/007/thread_pool.cpp b/docs/tutorials/007/thread_pool.cpp deleted file mode 100644 index 852b51ef232..00000000000 --- a/docs/tutorials/007/thread_pool.cpp +++ /dev/null @@ -1,277 +0,0 @@ - -// $Id$ - -#include "thread_pool.h" - -/* - We need this header so that we can invoke handle_input() on the objects we dequeue. - */ -#include "ace/Event_Handler.h" - - -/* - All we do here is initialize our active thread counter. - */ -Thread_Pool::Thread_Pool(void) - : active_threads_(0) -{ -} - -/* - Our open() method is a thin disguise around the ACE_Task<> activate() method. By - hiding activate() in this way, the users of Thread_Pool don't have to worry about - the thread configuration flags. - */ -int Thread_Pool::open( int _pool_size ) -{ - return this->activate(THR_NEW_LWP,_pool_size); -} - -/* - Closing the thread pool can be a tricky exercise. I've decided to take an easy approach - and simply enqueue a secret message for each thread we have active. - */ -int Thread_Pool::close( u_long flags ) -{ - ACE_UNUSED_ARG(flags); - - /* - Find out how many threads are currently active - */ - int counter = active_threads_.value(); - - /* - For each one of the active threads, enqueue a "null" event handler. Below, we'll - teach our svc() method that "null" means "shutdown". - */ - while( counter-- ) - { - this->enqueue( 0 ); - } - - /* - As each svc() method exits, it will decrement the active thread counter. We just wait - here for it to reach zero. Since we don't know how long it will take, we sleep for - a quarter-second or so between tries. - */ - while( active_threads_.value() ) - { - ACE_OS::sleep( ACE_Time_Value(0.25) ); - } - - return(0); -} - -/* - When an object wants to do work in the pool, it should call the enqueue() method. - We introduce the ACE_Message_Block here but, unfortunately, we seriously missuse it. - */ -int Thread_Pool::enqueue( ACE_Event_Handler * _handler ) -{ - /* - An ACE_Message_Block is a chunk of data. You put them into an ACE_Message_Queue. - ACE_Task<> has an ACE_Message_Queue built in. In fact, the parameter to ACE_Task<> - is passed directly to ACE_Message_Queue. If you look back at our header file you'll - see that we used ACE_MT_SYNCH as the parameter indicating that we want MultiThread - Synch safety. This allows us to safely put ACE_Message_Block objects into the - message queue in one thread and take them out in another. - */ - - /* - An ACE_Message_Block wants to have char* data. We don't have that. We could - cast our ACE_Event_Handler* directly to a char* but I wanted to be more explicit. - Since casting pointers around is a dangerous thing, I've gone out of my way here - to be very clear about what we're doing. - - First: Cast the handler pointer to a void pointer. You can't do any useful work - on a void pointer, so this is a clear message that we're making the - pointer unusable. - - Next: Cast the void pointer to a char pointer that the ACE_Message_Block will accept. - */ - void * v_data = (void*)_handler; - char * c_data = (char*)v_data; - - /* - Construct a new ACE_Message_Block. For efficiency, you might want to preallocate a - stack of these and reuse them. For simplicity, I'll just create what I need as I need it. - */ - ACE_Message_Block * mb = new ACE_Message_Block( c_data ); - - /* - Our putq() method is a wrapper around one of the enqueue methods of the ACE_Message_Queue - that we own. Like all good methods, it returns -1 if it fails for some reason. - */ - if( this->putq(mb) == -1 ) - { - /* - Another trait of the ACE_Message_Block objects is that they are reference counted. - Since they're designed to be passed around between various objects in several threads - we can't just delete them whenever we feel like it. The release() method is similar - to the destroy() method we've used elsewhere. It watches the reference count and will - delete the object when possible. - */ - mb->release(); - return(-1); - } - - return(0); -} - -/* - The "guard" concept is very powerful and used throughout multi-threaded applications. - A guard normally does some operation on an object at construction and the "opposite" - operation at destruction. For instance, when you guard a mutex (lock) object, the guard - will acquire the lock on construction and release it on destruction. In this way, your - method can simply let the guard go out of scope and know that the lock is released. - - Guards aren't only useful for locks however. In this application I've created two guard - objects for quite a different purpose. - */ - -/* - The Counter_Guard is constructed with a reference to the thread pool's active thread - counter. The guard increments the counter when it is created and decrements it at - destruction. By creating one of these in svc(), I know that the counter will be decremented - no matter how or where svc() returns. - */ -class Counter_Guard -{ -public: - Counter_Guard( Thread_Pool::counter_t & _counter ) - : counter_(_counter) - { - ++counter_; - } - - ~Counter_Guard(void) - { - --counter_; - } - -protected: - Thread_Pool::counter_t & counter_; -}; - -/* - My Message_Block_Guard is also a little non-traditional. It doesn't do anything in the - constructor but it's destructor ensures that the message block's release() method is called. - This is a cheap way to prevent a memory leak if I need an additional exit point in svc(). - */ -class Message_Block_Guard -{ -public: - Message_Block_Guard( ACE_Message_Block * & _mb ) - : mb_(_mb) - { - } - - ~Message_Block_Guard( void ) - { - mb_->release(); - } - -protected: - ACE_Message_Block * & mb_; -}; - -/* - Now we come to the svc() method. As I said, this is being executed in each thread of the - Thread_Pool. Here, we pull messages off of our built-in ACE_Message_Queue and cause them - to do work. - */ -int Thread_Pool::svc(void) -{ - /* - The getq() method takes a reference to a pointer. So... we need a pointer to give it - a reference to. - */ - ACE_Message_Block * mb; - - /* - Create the guard for our active thread counter object. No matter where we choose to - return() from svc(), we no know that the counter will be decremented. - */ - Counter_Guard counter_guard(active_threads_); - - /* - Get messages from the queue until we have a failure. There's no real good reason - for failure so if it happens, we leave immediately. - */ - while( this->getq(mb) != -1 ) - { - /* - A successful getq() will cause "mb" to point to a valid refernce-counted - ACE_Message_Block. We use our guard object here so that we're sure to call - the release() method of that message block and reduce it's reference count. - Once the count reaches zero, it will be deleted. - */ - Message_Block_Guard message_block_guard(mb); - - /* - As noted before, the ACE_Message_Block stores it's data as a char*. We pull that - out here and later turn it into an ACE_Event_Handler* - */ - char * c_data = mb->base(); - - /* - We've chosen to use a "null" value as an indication to leave. If the data we got - from the queue is not null then we have some work to do. - */ - if( c_data ) - { - /* - Once again, we go to great lengths to emphasize the fact that we're casting pointers - around in rather impolite ways. We could have cast the char* directly to an - ACE_Event_Handler* but then folks might think that's an OK thing to do. - - (Note: The correct way to use an ACE_Message_Block is to write data into it. - What I should have done was create a message block big enough to hold an - event handler pointer and then written the pointer value into the block. When - we got here, I would have to read that data back into a pointer. While politically - correct, it is also a lot of work. If you're careful you can get away with casting - pointers around.) - */ - void * v_data = (void*)c_data; - - ACE_Event_Handler * handler = (ACE_Event_Handler*)v_data; - - /* - Now that we finally have an event handler pointer, invoke it's handle_input() method. - Since we don't know it's handle, we just give it a default. That's OK because we - know that we're not using the handle in the method anyway. - */ - if( handler->handle_input(ACE_INVALID_HANDLE) == -1 ) - { - /* - Tell the handler that it's time to go home. The "normal" method for shutting - down a handler whose handler failed is to invoke handle_close(). This will - take care of cleaning it up for us. - Notice how we use the handler's get_handle() method to populate it's "handle" - parameter. Convenient isn't it? - */ - handler->handle_close(handler->get_handle(),0); - - /* - Also notice that we don't exit the svc() method here! The first time I did - this, I was exiting. After a few clients disconnect you have an empty - thread pool. Hard to do any more work after that... - */ - } - } - else - { - /* - If we get here, we were given a message block with "null" data. That is our - signal to leave, so we return(0) to leave gracefully. - */ - return(0); // Ok, shutdown request - } - - // message_block_guard goes out of scope here - // and releases the message_block instance. - } - - return(0); -} - diff --git a/docs/tutorials/007/thread_pool.h b/docs/tutorials/007/thread_pool.h deleted file mode 100644 index 12b9f14a44f..00000000000 --- a/docs/tutorials/007/thread_pool.h +++ /dev/null @@ -1,102 +0,0 @@ - -// $Id$ - -#ifndef THREAD_POOL_H -#define THREAD_POOL_H - -/* - In order to implement a thread pool, we have to have an object that can create - a thread. The ACE_Task<> is the basis for doing just such a thing. - */ -#include "ace/Task.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -/* - We need a forward reference for ACE_Event_Handler so that our enqueue() method - can accept a pointer to one. - */ -class ACE_Event_Handler; - -/* - Although we modified the rest of our program to make use of the thread pool - implementation, if you look closely you'll see that the changes were rather - minor. The "ACE way" is generally to create a helper object that abstracts - away the details not relevant to your application. That's what I'm trying - to do here by creating the Thread_Pool object. - */ -class Thread_Pool : public ACE_Task<ACE_MT_SYNCH> -{ -public: - - typedef ACE_Task<ACE_MT_SYNCH> inherited; - - /* - Provide an enumeration for the default pool size. By doing this, other objects - can use the value when they want a default. - */ - enum size_t - { - default_pool_size_ = 5 - }; - - // Basic constructor - Thread_Pool(void); - - /* - Opening the thread pool causes one or more threads to be activated. When activated, - they all execute the svc() method declared below. - */ - int open( int _pool_size = default_pool_size_ ); - - /* - Some compilers will complain that our open() above attempts to - override a virtual function in the baseclass. We have no - intention of overriding that method but in order to keep the - compiler quiet we have to add this method as a pass-thru to the - baseclass method. - */ - virtual int open(void * _void_data) - { return inherited::open(_void_data); } - - /* - */ - int close( u_long flags = 0 ); - - /* - To use the thread pool, you have to put some unit of work into it. Since we're - dealing with event handlers (or at least their derivatives), I've chosen to provide - an enqueue() method that takes a pointer to an ACE_Event_Handler. The handler's - handle_input() method will be called, so your object has to know when it is being - called by the thread pool. - */ - int enqueue( ACE_Event_Handler * _handler ); - - /* - Another handy ACE template is ACE_Atomic_Op<>. When parameterized, this allows - is to have a thread-safe counting object. The typical arithmetic operators are - all internally thread-safe so that you can share it across threads without worrying - about any contention issues. - */ - typedef ACE_Atomic_Op<ACE_Mutex,int> counter_t; - -protected: - - /* - Our svc() method will dequeue the enqueued event handler objects and invoke the - handle_input() method on each. Since we're likely running in more than one thread, - idle threads can take work from the queue while other threads are busy executing - handle_input() on some object. - */ - int svc(void); - - /* - We use the atomic op to keep a count of the number of threads in which our svc() - method is running. This is particularly important when we want to close() it down! - */ - counter_t active_threads_; -}; - -#endif // THREAD_POOL_H diff --git a/docs/tutorials/008/Makefile b/docs/tutorials/008/Makefile deleted file mode 100644 index 356d7f32f5f..00000000000 --- a/docs/tutorials/008/Makefile +++ /dev/null @@ -1,59 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = server directed_client broadcast_client - -FILES = - -BUILD = $(VBIN) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - - # Don't put anything below here. Between the "depend" target and fix.Makefile - # it's guaranteed to be lost! - - # This is inserted by the fix.Makefile script -include .depend diff --git a/docs/tutorials/008/broadcast_client.cpp b/docs/tutorials/008/broadcast_client.cpp deleted file mode 100644 index 2f754806d03..00000000000 --- a/docs/tutorials/008/broadcast_client.cpp +++ /dev/null @@ -1,72 +0,0 @@ - -// $Id$ - -#include "ace/SOCK_Dgram_Bcast.h" -#include "ace/INET_Addr.h" - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main(int argc,char *argv[] ) -{ - ACE_INET_Addr local((u_short)0); - - /* - Instead of creating the ACE_SOCK_Dgram we created last time, - we'll create an ACE_SOCK_Dgram_Bcast. "Bcast" means, of course, - "Broadcast". This ACE object is clever enough to go out to the - OS and find all of the network interfaces. When you send() - on a Dgram_Bcast, it will send the datagram out on all of those - interfaces. This is quiet handy if you do it on a multi-homed - host that plays router... - */ - ACE_SOCK_Dgram_Bcast dgram; - - if( dgram.open(local) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1); - } - - char buf[512]; - - sprintf(buf, "Hello World!"); - - /* - The only other difference between us and the directed client - is that we don't specify a host to receive the datagram. - Instead, we use the magic value "INADDR_BROADCAST". All hosts - are obliged to respond to datagrams directed to this address - the same as they would to datagrams sent to their hostname. - - Remember, the Dgram_Bcast will send a datagram to all interfaces - on the host. That's true even if the address is for a specific - host (and the host address makes sense for the interface). - The real power is in using an INADDR_BROADCAST addressed datagram - against all interfaces. - */ - - ACE_INET_Addr remote(PORT,INADDR_BROADCAST); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Sending (%s) to the server.\n",buf)); - - if( dgram.send(buf,strlen(buf)+1,remote) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1); - } - - if( dgram.recv(buf,sizeof(buf),remote) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1); - } - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server said: %s\n",buf)); - - /* - Using the "remote" object instance, find out where the server lives. - We could then save this address and use directed datagrams to chat - with the server for a while. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server can be found at: (%s:%d)\n", - remote.get_host_name(), PORT )); - - return(0); -} diff --git a/docs/tutorials/008/directed_client.cpp b/docs/tutorials/008/directed_client.cpp deleted file mode 100644 index 7fac216dbc3..00000000000 --- a/docs/tutorials/008/directed_client.cpp +++ /dev/null @@ -1,112 +0,0 @@ - -// $Id$ - -#include "ace/SOCK_Dgram.h" -#include "ace/INET_Addr.h" - -/* - Once again, we use the default server port. In a "real" system, - the server's port (or ports) would be published in some way so - that clients would know where to "look". We could even add entries - to the operating system's services file and use a service name - instead of a number. We'll come back to that in some other tutorial - though. For now, let's stay simple. - */ -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -/* - Our goal here is to develop a client that can send a datagram to - a server running on a known host. We'll use a command-line argument - to specify the hostname instead of hard-coding it. - */ -int main(int argc,char *argv[] ) -{ - /* - All datagrams have to have a point of origin. Since we intend to - transmit instead of receive, we initialize an address with zero - and let the OS choose a port for us. We could have chosen our - own value between 1025 and 65535 as long as it isn't already in use. - */ - ACE_INET_Addr local((u_short)0); - - /* - And here is our datagram object. - */ - ACE_SOCK_Dgram dgram; - - /* - Notice that this looks a lot like the server application. There's - no difference in creating server datagrams an client datagrams. - You can even use a zero-constructed address for your server datagram - as long as you tell the client where you're listening (eg -- by writting - into a file or some such). - */ - if( dgram.open(local) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1); - } - - /* - Yep. We've seen this before too... - */ - char buf[512]; - - /* - Ok, now we're doing something different. - */ - sprintf(buf, "Hello World!"); - - /* - Just like sending a telegram, we have to address our datagram. - Here, we create an address object at the desired port on the - chosen host. To keep us from crashing, we'll provide a default - host name if we aren't given one. - */ - ACE_INET_Addr remote(PORT, argc > 1 ? argv[1] : "localhost" ); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Sending (%s) to the server.\n",buf)); - /* - Now we send our buffer of stuff to the remote address. This is - just exactly what the server did after receiving a client message. - Datagrams are rather orthogonal that way: they don't generally make - much of a fuss about being either client or server. - */ - if( dgram.send(buf,strlen(buf)+1,remote) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1); - } - - /* - Now we've turned around and put ourselves into "server mode" by - invoking the recv() method. We now our server is going to send - us something, so we hang out here and wait for it. Because we - know datagrams are unreliable, there is a chance that the server - will respond but we won't hear. You might consider providing a - timeout on the recv() in that case. If recv() fails due to timeout - it will return -1 and you can then resend your query and attempt - the recv() again. - - Like the server application, we have to give the recv() an - uninitialized addr object so that we can find out who is talking - back to us. - */ - if( dgram.recv(buf,sizeof(buf),remote) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1); - } - - /* - Find out what the server had to say. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server said: %s\n",buf)); - - /* - Using the "remote" object instance, find out where the server lives. - We could then save this address and use directed datagrams to chat - with the server for a while. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server can be found at: (%s:%d)\n", - remote.get_host_name(), PORT )); - - return(0); -} diff --git a/docs/tutorials/008/page01.html b/docs/tutorials/008/page01.html deleted file mode 100644 index ebe24e9ecc8..00000000000 --- a/docs/tutorials/008/page01.html +++ /dev/null @@ -1,60 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 008</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In a lot of IPC programming, the clients know where the servers -are. A mail client, for instance, has a configuration file that says -where the mail host is. Your web browser has a "location" field that -you type into to give it a destination. - -<P>What if you have written a server application and then you execute it -on several systems in your network? All of the instances are probably -more or less equal to the client's point of view, so you don't want to -"configure" the clients to a single server each. Likewise, you -want the ability to add and remove servers at any time so you can't just -give the clients a list to choose from. - -<P>So... how do the clients know where the servers are? - -<P>Let 'em ask! - -<P>Datagrams are great for this. You can toss a datagram out onto -the network and any servers listening at the correct port will* hear it. -Like ACE_SOCK_Stream that we've seen before, you can get the peer address -from a datagram. With that, the server can send a response -back to the client. The client, in turn, can pull the peer address -out and know exactly where the server lives. - -<P>In this tutorial we'll develop three applications: a server listening -for datagrams, a client that can send to a known host and a client that -can send to the entire (sub)network. In the next tutorial, we'll -expand on this to make the server a bit more prudish. -<BR> - -<P><FONT SIZE=-1>* Actually, the servers <I>might</I> hear the datagram. -Datagrams are rather unreliable. (Sort of like some operating systems -I know.) Still, if the network traffic isn't too bad, they generally -get through. Your clients can always send out more queries if there -aren't any responses in a timely fashion.</FONT> - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial -Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/008/page02.html b/docs/tutorials/008/page02.html deleted file mode 100644 index 85b8c083d88..00000000000 --- a/docs/tutorials/008/page02.html +++ /dev/null @@ -1,237 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 008</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>The first thing we want to look at is <A HREF="server.cpp">server.cpp</A>. -This is a pretty simple application that listens for datagrams at a known -port and sends back a response. In order to implement a true "discovery" -mechanism, the server will have to be a little bit more picky about who -it responds to. We'll tackle that issue in the next tutorial though... - -<P> -<HR WIDTH="100%"> - -<P><TT>/*</TT> -<BR><TT> Our datagram server will, of course, need to create -a datagram.</TT> -<BR><TT> We'll also need an address object so that we know -where to listen.</TT> -<BR><TT> */</TT> -<BR><TT>#include "ace/SOCK_Dgram.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT> - -<P><TT>/*</TT> -<BR><TT> Use the typical TCP/IP port address for receiving -datagrams.</TT> -<BR><TT> */</TT> -<BR><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT> - -<P><TT>int main(int,char**)</TT> -<BR><TT>{</TT> -<BR><TT> /*</TT> -<BR><TT> This is where we'll listen -for datagrams coming from the</TT> -<BR><TT> clients. We'll give -this address to the open() method</TT> -<BR><TT> below to enable the listener.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr local(PORT);</TT> - -<P><TT> /*</TT> -<BR><TT> A simply constructed datagram -that we'll listen with.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_SOCK_Dgram dgram;</TT> - -<P><TT> /*</TT> -<BR><TT> Like most ACE objects, the -datagram has to be opened before</TT> -<BR><TT> it can be uses. Of course, --1 on failure.</TT> - -<P><TT> A datagram will fail to open -if there is already a datagram</TT> -<BR><TT> listening at the port we've -chosen. It *is* OK to open</TT> -<BR><TT> a datagram at a port where -there is an ACE_SOCK_Stream</TT> -<BR><TT> though. This is because -datagrams are UDP and SOCK_Stream</TT> -<BR><TT> is TCP and the two don't cross -paths.</TT> -<BR><TT> */</TT> -<BR><TT> if( dgram.open(local) == -1 )</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, -"%p\n", "open"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> /*</TT> -<BR><TT> Create a simple buffer to -receive the data. You generally need</TT> -<BR><TT> to provide a buffer big enough -for the largest datagram you</TT> -<BR><TT> expect to receive. Some -platforms will let you read a little</TT> -<BR><TT> and then some more later but -other platforms will throw out</TT> -<BR><TT> whatever part of the datagram -you don't get with the first</TT> -<BR><TT> read. (This is on a -per-datagram basis BTW.) The theoretical</TT> -<BR><TT> limit on a datagram is about -64k. The realistic limit (because</TT> -<BR><TT> of routers & such) is -much smaller. Choose your buffer size</TT> -<BR><TT> based on your application's -needs.</TT> -<BR><TT> */</TT> -<BR><TT> char buf[512];</TT> - -<P><TT> /*</TT> -<BR><TT> Unlike ACE_SOCK_Stream, datagrams -are unconnected. That is,</TT> -<BR><TT> there is no "virtual circuit" -between server and client.</TT> -<BR><TT> Because of this, the server -has to provide a placeholder</TT> -<BR><TT> for the OS to fill in the -source (client) address information</TT> -<BR><TT> on the recv. You can -initialize this INET_Addr to anything,</TT> -<BR><TT> it will be overwritten when -the data arrives.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr remote;</TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server -daemon\n"));</TT> - -<P><TT> /*</TT> -<BR><TT> Receive datagrams as long -as we're able.</TT> -<BR><TT> */</TT> -<BR><TT> while( dgram.recv(buf,sizeof(buf),remote) != --1 )</TT> -<BR><TT> {</TT> -<BR><TT> /*</TT> -<BR><TT> Display -a brief message about our progress. Notice how we</TT> -<BR><TT> use -the 'remote' object to display the address of the client.</TT> -<BR><TT> With -an ACE_SOCK_Stream we used get_remote_addr() to get the</TT> -<BR><TT> address -the socket is connected to. Because datagrams are</TT> -<BR><TT> unconnected, -we use the addr object provided to recv().</TT> -<BR><TT> */</TT> -<BR><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) Data (%s) from client (%s)\n", buf, remote.get_host_name()));</TT> - -<P><TT> /*</TT> -<BR><TT> To -respond to the client's query, we have to become a client</TT> -<BR><TT> ourselves. -To do so, we need an anonymous local address from</TT> -<BR><TT> which -we'll send the response and a datagram in which to send</TT> -<BR><TT> it. -(An anonymous address is simply one where we let the OS</TT> -<BR><TT> choose -a port for us. We really don't care what it is.O</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr -local((u_short)0);</TT> -<BR><TT> ACE_SOCK_Dgram client;</TT> - -<P><TT> /*</TT> -<BR><TT> Open -up our response datagram as always.</TT> -<BR><TT> */</TT> -<BR><TT> if( client.open(local) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "client open"),-1);</TT> -<BR><TT> -return(0);</TT> -<BR><TT> }</TT> - -<P><TT> /*</TT> -<BR><TT> Build -a witty response...</TT> -<BR><TT> */</TT> -<BR><TT> sprintf(buf,"I am here");</TT> - -<P><TT> /*</TT> -<BR><TT> and -send it to the client. Notice the symetry with the recv()</TT> -<BR><TT> method. -Again, the unconnected nature of datagrams forces</TT> -<BR><TT> us -to specify an address object with each read/write operation.</TT> -<BR><TT> In -the case of read (recv()) that's where the OS stuffs the</TT> -<BR><TT> address -of the datagram sender. In the case of write (send())</TT> -<BR><TT> that -we're doing here, the address is where we want the network</TT> -<BR><TT> to -deliver the data.</TT> - -<P><TT> Of -course, we're assuming that the client will be listening</TT> -<BR><TT> for -our reply...</TT> -<BR><TT> */</TT> -<BR><TT> if( client.send(buf,strlen(buf)+1,remote) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT> -<BR><TT> -return(0);</TT> -<BR><TT> }</TT> -<BR><TT> }</TT> - -<P><TT> return(0);</TT> -<BR><TT>}</TT> - -<P> -<HR WIDTH="100%"> - -<P>And that's really all there is to it. Obviously there is some -room for improvement. The most blatant is the somewhat small buffer -size for receiving the datagram. I've never been able to get a solid -answer on datagram sizes. The theoretical limit is just under 64k -but you have to deal with fragmentation. Some readings indicate that -8k is a reasonable size, others go much smaller. My general rule -of thumb is to keep datagrams relatively small (eg -- under 8k or so) and -test a lot. If you find that your routers are fragmenting your larger -datagrams, back off to something smaller. Of course, if you must -send 100k and can only do so 1k at a time, you'll have to worry about retransmissions -& reordering. At that point, you might consider going to TCP. -Remember: datagrams are unreliable! Don't try to make 'em do -something they werent' designed for! - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/008/page03.html b/docs/tutorials/008/page03.html deleted file mode 100644 index b1faf3b7287..00000000000 --- a/docs/tutorials/008/page03.html +++ /dev/null @@ -1,187 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 008</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In <A HREF="directed_client.cpp">directed_client.cpp</A> we create a -client that knows how to send a datagram to a server on a known host. -This is a good thing if you know where the server lives and want to have -a conversation. The Unix <I>talk</I> utilitiy, for instance, -could be written this way. - -<P> -<HR WIDTH="100%"> - -<P><TT>#include "ace/SOCK_Dgram.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT> - -<P><TT>/*</TT> -<BR><TT> Once again, we use the default server port. -In a "real" system,</TT> -<BR><TT> the server's port (or ports) would be published in -some way so</TT> -<BR><TT> that clients would know where to "look". We -could even add entries</TT> -<BR><TT> to the operating system's services file and use a -service name</TT> -<BR><TT> instead of a number. We'll come back to that -in some other tutorial</TT> -<BR><TT> though. For now, let's stay simple.</TT> -<BR><TT> */</TT> -<BR><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT> - -<P><TT>/*</TT> -<BR><TT> Our goal here is to develop a client that can send -a datagram to</TT> -<BR><TT> a server running on a known host. We'll use -a command-line argument</TT> -<BR><TT> to specify the hostname instead of hard-coding it.</TT> -<BR><TT> */</TT> -<BR><TT>int main(int argc,char *argv[] )</TT> -<BR><TT>{</TT> -<BR><TT> /*</TT> -<BR><TT> All -datagrams have to have a point of origin. Since we intend to</TT> -<BR><TT> transmit -instead of receive, we initialize an address with zero</TT> -<BR><TT> and -let the OS choose a port for us. We could have chosen our</TT> -<BR><TT> own -value between 1025 and 65535 as long as it isn't already in use.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr -local((u_short)0);</TT> - -<P><TT> /*</TT> -<BR><TT> And -here is our datagram object.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_SOCK_Dgram dgram;</TT> -<BR><TT> </TT> -<BR><TT> /*</TT> -<BR><TT> Notice -that this looks a lot like the server application. There's</TT> -<BR><TT> no -difference in creating server datagrams an client datagrams.</TT> -<BR><TT> You -can even use a zero-constructed address for your server datagram</TT> -<BR><TT> as -long as you tell the client where you're listening (eg -- by writting</TT> -<BR><TT> into -a file or some such).</TT> -<BR><TT> */</TT> -<BR><TT> if( dgram.open(local) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> /*</TT> -<BR><TT> Yep. -We've seen this before too...</TT> -<BR><TT> */</TT> -<BR><TT> char buf[512];</TT> - -<P><TT> /*</TT> -<BR><TT> Ok, -now we're doing something different.</TT> -<BR><TT> */</TT> -<BR><TT> sprintf(buf, "Hello -World!");</TT> - -<P><TT> /*</TT> -<BR><TT> Just -like sending a telegram, we have to address our datagram.</TT> -<BR><TT> Here, -we create an address object at the desired port on the</TT> -<BR><TT> chosen -host. To keep us from crashing, we'll provide a default</TT> -<BR><TT> host -name if we aren't given one.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr -remote(PORT, argc > 1 ? argv[1] : "localhost" );</TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) Sending (%s) to the server.\n",buf));</TT> -<BR><TT> /*</TT> -<BR><TT> -Now we send our buffer of stuff to the remote address. This is</TT> -<BR><TT> -just exactly what the server did after receiving a client message.</TT> -<BR><TT> -Datagrams are rather orthogonal that way: they don't generally make</TT> -<BR><TT> -much of a fuss about being either client or server.</TT> -<BR><TT> */</TT> -<BR><TT> if( dgram.send(buf,strlen(buf)+1,remote) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> /*</TT> -<BR><TT> Now -we've turned around and put ourselves into "server mode" by</TT> -<BR><TT> invoking -the recv() method. We now our server is going to send</TT> -<BR><TT> us -something, so we hang out here and wait for it. Because we</TT> -<BR><TT> know -datagrams are unreliable, there is a chance that the server</TT> -<BR><TT> will -respond but we won't hear. You might consider providing a</TT> -<BR><TT> timeout -on the recv() in that case. If recv() fails due to timeout</TT> -<BR><TT> it -will return -1 and you can then resend your query and attempt</TT> -<BR><TT> the -recv() again.</TT> -<BR><TT> */</TT> -<BR><TT> if( dgram.recv(buf,sizeof(buf),remote) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> /*</TT> -<BR><TT> Find -out what the server had to say.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) The server said: %s\n",buf));</TT> - -<P><TT> return(0);</TT> -<BR><TT>}</TT> - -<P> -<HR WIDTH="100%"> - -<P>That's all neat and good but the point of what we're doing here is not -to talk to a server we know about but to discover servers we don't know -about. Now, you could send a directed datagram to every possible -host address on your network but that's not a very nice thing to do. -On the next page, we'll find out the right approach... - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/008/page04.html b/docs/tutorials/008/page04.html deleted file mode 100644 index 4a634b56a4b..00000000000 --- a/docs/tutorials/008/page04.html +++ /dev/null @@ -1,156 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 008</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<BR> -<BR> In <A HREF="broadcast_client.cpp">broadcast_client.cpp</A> we -find out how to send a single datagram to every host on our (sub)network. -I have to say <I>(sub)network</I> because broadcast datagrams typically -are not passed through routers. So, if your network admin has divided -up your network into subnets, your broadcasts will likey only stay on the -subnet you're a part of. - -<P>I've only commented the parts that are different from the directed_client. - -<P> -<HR WIDTH="100%"> - -<P><TT>#include "ace/SOCK_Dgram_Bcast.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT> - -<P><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT> - -<P><TT>int main(int argc,char *argv[] )</TT> -<BR><TT>{</TT> -<BR><TT> ACE_INET_Addr -local((u_short)0);</TT> - -<P><TT> /*</TT> -<BR><TT> Instead -of creating the ACE_SOCK_Dgram we created last time,</TT> -<BR><TT> we'll -create an ACE_SOCK_Dgram_Bcast. "Bcast" means, of course,</TT> -<BR><TT> "Broadcast". -This ACE object is clever enough to go out to the</TT> -<BR><TT> OS -and find all of the network interfaces. When you send()</TT> -<BR><TT> on -a Dgram_Bcast, it will send the datagram out on all of those</TT> -<BR><TT> interfaces. -This is quiet handy if you do it on a multi-homed</TT> -<BR><TT> host -that plays router...</TT> -<BR><TT> */</TT> -<BR><TT> ACE_SOCK_Dgram_Bcast -dgram;</TT> - -<P><TT> if( dgram.open(local) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> char buf[512];</TT> - -<P><TT> sprintf(buf, "Hello World!");</TT> - -<P><TT> /*</TT> -<BR><TT> The -only other difference between us and the directed client</TT> -<BR><TT> is -that we don't specify a host to receive the datagram.</TT> -<BR><TT> Instead, -we use the magic value "INADDR_BROADCAST". All hosts</TT> -<BR><TT> are -obliged to respond to datagrams directed to this address</TT> -<BR><TT> the -same as they would to datagrams sent to their hostname.</TT> - -<P><TT> Remember, -the Dgram_Bcast will send a datagram to all interfaces</TT> -<BR><TT> on -the host. That's true even if the address is for a specific</TT> -<BR><TT> host -(and the host address makes sense for the interface).</TT> -<BR><TT> The -real power is in using an INADDR_BROADCAST addressed datagram</TT> -<BR><TT> against -all interfaces.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_INET_Addr -remote(PORT,INADDR_BROADCAST);</TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) Sending (%s) to the server.\n",buf));</TT> -<BR><TT> </TT> -<BR><TT> if( dgram.send(buf,strlen(buf)+1,remote) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> if( dgram.recv(buf,sizeof(buf),remote) -== -1 )</TT> -<BR><TT> {</TT> -<BR><TT> -ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1);</TT> -<BR><TT> }</TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) The server said: %s\n",buf));</TT> - -<P><TT> /*</TT> -<BR><TT> Using -the <I>remote</I> object instance, find out where the server lives.</TT> -<BR><TT> We -could then save this address and use directed datagrams to chat</TT> -<BR><TT> with -the server for a while.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_DEBUG ((LM_DEBUG, -"(%P|%t) The server can be found at: (%s:%d)\n",</TT> -<BR><TT> -remote.get_host_addr(), PORT ));</TT> -<BR><TT> </TT> -<BR><TT> return(0);</TT> -<BR><TT>}</TT> - -<P> -<HR WIDTH="100%"> - -<P> About that subnet thing: -<BLOCKQUOTE>If you run this client on a host that has multiple network -interfaces, the broadcast will go to all of those (sub)networks. -What do you do, though, if you need to get past a router? My advice -is to write a server that will run on hosts on both sides of your router. -When a server on one side of the router receives a broadcast, it would -send a directed datagram to it's counterpart on the other side of the router. -The counterpart would then re-broadcast the original datagram on that sub-net. -Cheap, simple and effective.</BLOCKQUOTE> -One final word of warning: -<BLOCKQUOTE>When creating your broadcast datagrams you may see something -like this: <I>ACE_SOCK_Dgram_Bcast::mk_broadcast: Broadcast is not -enable for this interface.: Unknown error</I>. There are some interfaces -(ppp, slip) that don't support broadcast datagrams. That's what you're -seeing here.</BLOCKQUOTE> - -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/008/page05.html b/docs/tutorials/008/page05.html deleted file mode 100644 index f8c4603668a..00000000000 --- a/docs/tutorials/008/page05.html +++ /dev/null @@ -1,43 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 008</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<BR> -<BR>That's it for this tutorial. In the next one we'll add some intelligence -to the data put into the datagrams. By doing so, we'll be able to -classify our clients and servers into groups. By combining the data -content and the server's port we can get fairly fine-grained control over -who talks to who. - -<P>For you convenience: -<UL> -<LI> -<A HREF="server.cpp">server.cpp</A></LI> - -<LI> -<A HREF="directed_client.cpp">directed_client.cpp</A></LI> - -<LI> -<A HREF="broadcast_client.cpp">broadcast_client.cpp</A></LI> - -<LI> -<A HREF="Makefile">Makefile</A></LI> -</UL> - -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/008/server.cpp b/docs/tutorials/008/server.cpp deleted file mode 100644 index e702b1b93bb..00000000000 --- a/docs/tutorials/008/server.cpp +++ /dev/null @@ -1,128 +0,0 @@ - -// $Id$ - -/* - Our datagram server will, of course, need to create a datagram. - We'll also need an address object so that we know where to listen. - */ -#include "ace/SOCK_Dgram.h" -#include "ace/INET_Addr.h" - -/* - Use the typical TCP/IP port address for receiving datagrams. - */ -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main(int,char**) -{ - /* - This is where we'll listen for datagrams coming from the - clients. We'll give this address to the open() method - below to enable the listener. - */ - ACE_INET_Addr local(PORT); - - /* - A simply constructed datagram that we'll listen with. - */ - ACE_SOCK_Dgram dgram; - - /* - Like most ACE objects, the datagram has to be opened before - it can be uses. Of course, -1 on failure. - - A datagram will fail to open if there is already a datagram - listening at the port we've chosen. It *is* OK to open - a datagram at a port where there is an ACE_SOCK_Stream - though. This is because datagrams are UDP and SOCK_Stream - is TCP and the two don't cross paths. - */ - if( dgram.open(local) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"),-1); - } - - /* - Create a simple buffer to receive the data. You generally need - to provide a buffer big enough for the largest datagram you - expect to receive. Some platforms will let you read a little - and then some more later but other platforms will throw out - whatever part of the datagram you don't get with the first - read. (This is on a per-datagram basis BTW.) The theoretical - limit on a datagram is about 64k. The realistic limit (because - of routers & such) is much smaller. Choose your buffer size - based on your application's needs. - */ - char buf[512]; - - /* - Unlike ACE_SOCK_Stream, datagrams are unconnected. That is, - there is no "virtual circuit" between server and client. - Because of this, the server has to provide a placeholder - for the OS to fill in the source (client) address information - on the recv. You can initialize this INET_Addr to anything, - it will be overwritten when the data arrives. - */ - ACE_INET_Addr remote; - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server daemon\n")); - - /* - Receive datagrams as long as we're able. - */ - while( dgram.recv(buf,sizeof(buf),remote) != -1 ) - { - /* - Display a brief message about our progress. Notice how we - use the 'remote' object to display the address of the client. - With an ACE_SOCK_Stream we used get_remote_addr() to get the - address the socket is connected to. Because datagrams are - unconnected, we use the addr object provided to recv(). - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data (%s) from client (%s)\n", buf, remote.get_host_name())); - - /* - To respond to the client's query, we have to become a client - ourselves. To do so, we need an anonymous local address from - which we'll send the response and a datagram in which to send - it. (An anonymous address is simply one where we let the OS - choose a port for us. We really don't care what it is.O - */ - ACE_INET_Addr local((u_short)0); - ACE_SOCK_Dgram client; - - /* - Open up our response datagram as always. - */ - if( client.open(local) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "client open"),-1); - return(0); - } - - /* - Build a witty response... - */ - sprintf(buf,"I am here"); - - /* - and send it to the client. Notice the symetry with the recv() - method. Again, the unconnected nature of datagrams forces - us to specify an address object with each read/write operation. - In the case of read (recv()) that's where the OS stuffs the - address of the datagram sender. In the case of write (send()) - that we're doing here, the address is where we want the network - to deliver the data. - - Of course, we're assuming that the client will be listening - for our reply... - */ - if( client.send(buf,strlen(buf)+1,remote) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1); - return(0); - } - } - - return(0); -} diff --git a/docs/tutorials/009/Makefile b/docs/tutorials/009/Makefile deleted file mode 100644 index 0a3070f89db..00000000000 --- a/docs/tutorials/009/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = server directed_client broadcast_client - -FILES = - -BUILD = $(VBIN) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -bli0 -l80 -fca -fc1 -cli0 -cdb < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - - # Don't put anything below here. Between the "depend" target and fix.Makefile - # it's guaranteed to be lost! - - # This is inserted by the fix.Makefile script -include .depend diff --git a/docs/tutorials/009/broadcast_client.cpp b/docs/tutorials/009/broadcast_client.cpp deleted file mode 100644 index 76ff454d066..00000000000 --- a/docs/tutorials/009/broadcast_client.cpp +++ /dev/null @@ -1,39 +0,0 @@ - -// $Id$ - -#include "ace/SOCK_Dgram_Bcast.h" -#include "ace/INET_Addr.h" - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main (int argc, char *argv[]) -{ - ACE_INET_Addr local ((u_short) 0); - ACE_INET_Addr remote (PORT, INADDR_BROADCAST); - ACE_SOCK_Dgram_Bcast dgram; - - if (dgram.open (local) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - char buf[512]; - - sprintf (buf, argc > 1 ? argv[1] : "Hello World!"); - - if (dgram.send (buf, strlen (buf) + 1, remote) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - - ACE_Time_Value timeout (2, 0); - if (dgram.recv (buf, sizeof (buf), remote, 0, &timeout) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"), -1); - } - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server at (%s) said (%s)\n", - remote.get_host_name (), buf)); - - return (0); -} diff --git a/docs/tutorials/009/directed_client.cpp b/docs/tutorials/009/directed_client.cpp deleted file mode 100644 index 7156286bec1..00000000000 --- a/docs/tutorials/009/directed_client.cpp +++ /dev/null @@ -1,52 +0,0 @@ - -// $Id$ - -#include "ace/SOCK_Dgram.h" -#include "ace/INET_Addr.h" - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main (int argc, char *argv[]) -{ - ACE_INET_Addr local ((u_short) 0); - ACE_INET_Addr remote (PORT, argc > 1 ? argv[1] : "localhost"); - ACE_SOCK_Dgram dgram; - - if (dgram.open (local) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - char buf[512]; - - /* - In order to conform to the "protocol" requried by the server, - we allow the user to specify a signature. A default matching - the server's default is also available. - */ - sprintf (buf, argc > 2 ? argv[2] : "Hello World!"); - - if (dgram.send (buf, strlen (buf) + 1, remote) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), -1); - } - - /* - Because we may have sent a signature that the server doesn't - honor, we have to have some way to get out of the recv(). - Most ACE objects that have potential for infinite blocking - give you the option of providing a timeout. recv() is no - exception. Here, we construct an ACE_Time_Value representing - two seconds and no micro-seconds. If recv() fails to get - a response within the two seconds, it will return -1. - */ - ACE_Time_Value timeout (2, 0); - if (dgram.recv (buf, sizeof (buf), remote, 0, &timeout) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"), -1); - } - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server said (%s)\n", buf)); - - return (0); -} diff --git a/docs/tutorials/009/page01.html b/docs/tutorials/009/page01.html deleted file mode 100644 index 77bacc3d4cc..00000000000 --- a/docs/tutorials/009/page01.html +++ /dev/null @@ -1,52 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 009</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 009</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams again</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In our previous tutorial, we created a datagram listener and a couple -of clients that would send it datagrams. That server would respond -to any datagram sent to the TCP/IP port at which the server was listening. -What we really want to do, however, is to have the server only respond -to clients that meet some criteria. - -<P>Why is this important? - -<P>Imagine you're writting a distributed system that will have many server -applications. Each of those will probably listen at different (and -well-known) TCP/IP addresses so that clients can find each server -without confusion. However... In a large system you might have -several <I>versions</I> of the same server running at the same time*. -You probably don't want those servers running at different addresses since -that breaks the well-known address requirement. - -<P>By creating a datagram listener similar to the last tutorial, a client -can send broadcast datagrams to locate all of the servers listening at -the well-known address. By adding a thin protocol layer into -the datagram contents, the servers can be selective about which clients -they respond to. Thus, if each client sends its version signature -in the broadcast, then the servers can choose to respond only to clients -with matching versions. - -<P><FONT SIZE=-1>*Note: I'm making the assumption that your multiple -server versions will be running on different hosts since you can only have -one server listening at the well-known address on a given host.</FONT> - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/009/page02.html b/docs/tutorials/009/page02.html deleted file mode 100644 index e2997a16409..00000000000 --- a/docs/tutorials/009/page02.html +++ /dev/null @@ -1,130 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 009</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 009</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams again</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Let's take a look at our new <A HREF="server.cpp">server.cpp</A> where -we add in just a bit of code to examine the datagram contents before responding. - -<P> -<HR WIDTH="100%"><TT></TT> - -<P><TT>/*</TT> -<BR><TT> The actual datagram operations here are exactly the -same as those used in</TT> -<BR><TT> the previous tutorial. What we've added is some -logic that will prevent</TT> -<BR><TT> this server from responding to just any old datagram. -I'll limit my</TT> -<BR><TT> comments to those pieces of code.</TT> -<BR><TT> */</TT><TT></TT> - -<P><TT>#include "ace/SOCK_Dgram.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT><TT></TT> - -<P><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT><TT></TT> - -<P><TT>/*</TT> -<BR><TT> In order to be more selective, our server will be -started with a</TT> -<BR><TT> "signature". If none is given, we'll use the -one here instead.</TT> -<BR><TT> */</TT> -<BR><TT>static const char *default_signature = "Hello World!";</TT><TT></TT> - -<P><TT>int main (int argc, char *argv[])</TT> -<BR><TT>{</TT> -<BR><TT> ACE_INET_Addr local (PORT);</TT> -<BR><TT> ACE_SOCK_Dgram dgram;</TT><TT></TT> - -<P><TT> if (dgram.open (local) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> char buf[512];</TT> -<BR><TT> ACE_INET_Addr remote;</TT><TT></TT> - -<P><TT> while (dgram.recv (buf, sizeof (buf), remote) != -1)</TT> -<BR><TT> {</TT> -<BR><TT> /*</TT> -<BR><TT> What did the client say?</TT> -<BR><TT> */</TT> -<BR><TT> ACE_DEBUG ((LM_DEBUG, "(%P|%t) Received (%s) -from (%s)\n", buf, remote.get_host_name ()));</TT><TT></TT> - -<P><TT> /*</TT> -<BR><TT> Use a simple string-op to -decide if the client is one of our own. Of</TT> -<BR><TT> course, you could have sent -numeric values or even a struct of data. For</TT> -<BR><TT> this simple exercise, however, -strings are just fine.</TT> -<BR><TT> */</TT> -<BR><TT> if (ACE_OS::strcmp (buf, argc > 1 ? argv[1] -: default_signature))</TT> -<BR><TT> {</TT> -<BR><TT> /*</TT> -<BR><TT> If the client -didn't say something we like then log it and move on.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_DEBUG ((LM_DEBUG,</TT> -<BR><TT> -"(%P|%t) Client query does not match our signature (%s). Response -not sent.\n",</TT> -<BR><TT> -argc > 1 ? argv[1] : default_signature));</TT> -<BR><TT> }</TT> -<BR><TT> else</TT> -<BR><TT> {</TT> -<BR><TT> /*</TT> -<BR><TT> As before, we -respond to the client's query.</TT> -<BR><TT> */</TT><TT></TT> - -<P><TT> ACE_INET_Addr local ((u_short) 0);</TT> -<BR><TT> ACE_SOCK_Dgram client;</TT> -<BR><TT> if (client.open (local) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN -((LM_ERROR, "%p\n", "response open"), -1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> sprintf (buf, "I am here");</TT> -<BR><TT> if (client.send (buf, strlen (buf) -+ 1, remote) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN -((LM_ERROR, "%p\n", "response send"), -1);</TT> -<BR><TT> }</TT> -<BR><TT> }</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> return (0);</TT> -<BR><TT>}</TT><TT></TT> - -<P> -<HR WIDTH="100%"> - -<P>Let's move on and see what changes the clients require... - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/009/page03.html b/docs/tutorials/009/page03.html deleted file mode 100644 index 447bf38d497..00000000000 --- a/docs/tutorials/009/page03.html +++ /dev/null @@ -1,100 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 009</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 009</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams again</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Our new <A HREF="directed_client.cpp">directed_client.cpp</A> -is very much like our previous one. The primary difference is the -addition of a timeout to the recv() call so that we can exit somewhat gracefully -if the server doesn't like what we have to say. - -<P> -<HR WIDTH="100%"><TT></TT> - -<P><TT>#include "ace/SOCK_Dgram.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT><TT></TT> - -<P><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT><TT></TT> - -<P><TT>int main (int argc, char *argv[])</TT> -<BR><TT>{</TT> -<BR><TT> ACE_INET_Addr local ((u_short) 0);</TT> -<BR><TT> ACE_INET_Addr remote (PORT, argc > 1 ? argv[1] : "localhost");</TT> -<BR><TT> ACE_SOCK_Dgram dgram;</TT><TT></TT> - -<P><TT> if (dgram.open (local) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> char buf[512];</TT><TT></TT> - -<P><TT> /*</TT> -<BR><TT> In order to conform to the "protocol" -requried by the server,</TT> -<BR><TT> we allow the user to specify a signature. -A default matching</TT> -<BR><TT> the server's default is also available.</TT> -<BR><TT> */</TT> -<BR><TT> sprintf (buf, argc > 2 ? argv[2] : "Hello World!");</TT><TT></TT> - -<P><TT> if (dgram.send (buf, strlen (buf) + 1, remote) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> /*</TT> -<BR><TT> Because we may have sent a signature that -the server doesn't</TT> -<BR><TT> honor, we have to have some way to get -out of the recv().</TT> -<BR><TT> Most ACE objects that have potential for -infinite blocking</TT> -<BR><TT> give you the option of providing a timeout. -recv() is no</TT> -<BR><TT> exception. Here, we construct an -ACE_Time_Value representing</TT> -<BR><TT> two seconds and no micro-seconds. -If recv() fails to get</TT> -<BR><TT> a response within the two seconds, it -will return -1.</TT> -<BR><TT> */</TT> -<BR><TT> ACE_Time_Value timeout (2, 0);</TT> -<BR><TT> if (dgram.recv (buf, sizeof (buf), remote, 0, &timeout) -== -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server said (%s)\n", buf));</TT><TT></TT> - -<P><TT> return (0);</TT> -<BR><TT>}</TT> - -<P> -<HR WIDTH="100%"> - -<P>On the next page, we see that the directed_client gets similar upgrades. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/009/page04.html b/docs/tutorials/009/page04.html deleted file mode 100644 index e1875503b8c..00000000000 --- a/docs/tutorials/009/page04.html +++ /dev/null @@ -1,74 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 009</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 009</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams again</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>As you can see in <A HREF="broadcast_client.cpp">broadcast_client.cpp</A>, -there isn't enough difference to even comment on! Look back to the -Tutorial 8 version of this file. The only difference is the addition -of the timeout variable passed to recv(). - -<P> -<HR WIDTH="100%"><TT></TT> - -<P><TT>#include "ace/SOCK_Dgram_Bcast.h"</TT> -<BR><TT>#include "ace/INET_Addr.h"</TT><TT></TT> - -<P><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT><TT></TT> - -<P><TT>int main (int argc, char *argv[])</TT> -<BR><TT>{</TT> -<BR><TT> ACE_INET_Addr local ((u_short) 0);</TT> -<BR><TT> ACE_INET_Addr remote (PORT, INADDR_BROADCAST);</TT> -<BR><TT> ACE_SOCK_Dgram_Bcast dgram;</TT><TT></TT> - -<P><TT> if (dgram.open (local) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> char buf[512];</TT><TT></TT> - -<P><TT> sprintf (buf, argc > 1 ? argv[1] : "Hello World!");</TT><TT></TT> - -<P><TT> if (dgram.send (buf, strlen (buf) + 1, remote) == -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> ACE_Time_Value timeout (2, 0);</TT> -<BR><TT> if (dgram.recv (buf, sizeof (buf), remote, 0, &timeout) -== -1)</TT> -<BR><TT> {</TT> -<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"), --1);</TT> -<BR><TT> }</TT><TT></TT> - -<P><TT> ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server at (%s) said (%s)\n",</TT> -<BR><TT> -remote.get_host_name (), buf));</TT><TT></TT> - -<P><TT> return (0);</TT> -<BR><TT>}</TT> - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/009/page05.html b/docs/tutorials/009/page05.html deleted file mode 100644 index 771e113e961..00000000000 --- a/docs/tutorials/009/page05.html +++ /dev/null @@ -1,50 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 009</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 009</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams again</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In this tutorial we've expanded on Tutorial 8 to provide a more discriminating -server application. The changes to the clients were trivial, amounting -to not much more than the addition of a timeout when reading a server's -potential response. The server change was a bit more since it had -to compare the clients' query with it's own signature. - -<P>In a "real" system, the signatures you swap would probably include version -information. You could even use a major/minor scheme where an exact -match isn't necessary. Another upgrade might be to have a set of -signatures at one or both ends of the conversation. The level of -service provided by the server would be determined by the signature pair -match. - -<P>Here's the final file list: -<UL> -<LI> -<A HREF="Makefile">Makefile</A></LI> - -<LI> -<A HREF="server.cpp">server.cpp</A></LI> - -<LI> -<A HREF="directed_client.cpp">directed_client.cpp</A></LI> - -<LI> -<A HREF="broadcast_client.cpp">broadcast_client.cpp</A></LI> -</UL> - -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/009/server.cpp b/docs/tutorials/009/server.cpp deleted file mode 100644 index f73c7fd4ad3..00000000000 --- a/docs/tutorials/009/server.cpp +++ /dev/null @@ -1,78 +0,0 @@ - -// $Id$ - -/* - The actual datagram operations here are exactly the same as those used in - the previous tutorial. What we've added is some logic that will prevent - this server from responding to just any old datagram. I'll limit my - comments to those pieces of code. - */ - -#include "ace/SOCK_Dgram.h" -#include "ace/INET_Addr.h" - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -/* - In order to be more selective, our server will be started with a - "signature". If none is given, we'll use the one here instead. - */ -static const char *default_signature = "Hello World!"; - -int main (int argc, char *argv[]) -{ - ACE_INET_Addr local (PORT); - ACE_SOCK_Dgram dgram; - - if (dgram.open (local) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - char buf[512]; - ACE_INET_Addr remote; - - while (dgram.recv (buf, sizeof (buf), remote) != -1) - { - /* - What did the client say? - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Received (%s) from (%s)\n", buf, remote.get_host_name ())); - - /* - Use a simple string-op to decide if the client is one of our own. Of - course, you could have sent numeric values or even a struct of data. For - this simple exercise, however, strings are just fine. - */ - if (ACE_OS::strcmp (buf, argc > 1 ? argv[1] : default_signature)) - { - /* - If the client didn't say something we like then log it and move on. - */ - ACE_DEBUG ((LM_DEBUG, - "(%P|%t) Client query does not match our signature (%s). Response not sent.\n", - argc > 1 ? argv[1] : default_signature)); - } - else - { - /* - As before, we respond to the client's query. - */ - - ACE_INET_Addr local ((u_short) 0); - ACE_SOCK_Dgram client; - if (client.open (local) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "response open"), -1); - } - - sprintf (buf, "I am here"); - if (client.send (buf, strlen (buf) + 1, remote) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "response send"), -1); - } - } - } - - return (0); -} diff --git a/docs/tutorials/010/Makefile b/docs/tutorials/010/Makefile deleted file mode 100644 index d52722d4994..00000000000 --- a/docs/tutorials/010/Makefile +++ /dev/null @@ -1,59 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = message_queue - -FILES = -FILES += task - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES)) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../007/fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include .depend diff --git a/docs/tutorials/010/block.h b/docs/tutorials/010/block.h deleted file mode 100644 index 583886872cb..00000000000 --- a/docs/tutorials/010/block.h +++ /dev/null @@ -1,56 +0,0 @@ - -// $Id$ - -#ifndef BLOCK_H -#define BLOCK_H - -#include "ace/Message_Block.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -/* - This simple ACE_Message_Block derivative will inform us of it's construction - and destruction. We'll use this to assure ourselves that we don't have any - memory leaks. In a real application, of course, this isn't necessary. - */ -class Block : public ACE_Message_Block -{ -public: - Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - Block (size_t size) - : ACE_Message_Block (size) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - virtual ~ Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block dtor 0x%x\n", (void *) this)); - } -}; - -#endif - - - - - - - - - - - - - - - - - - diff --git a/docs/tutorials/010/message_queue.cpp b/docs/tutorials/010/message_queue.cpp deleted file mode 100644 index c52273a134b..00000000000 --- a/docs/tutorials/010/message_queue.cpp +++ /dev/null @@ -1,93 +0,0 @@ - -// $Id$ - -/* - To illustrate the ACE_Message_Queue, we use a derivative of ACE_Task<>. We - also derive from ACE_Message_Block to show that we don't have memory leaks. - */ -#include "task.h" -#include "block.h" - -int run_test( int iterations, int threads ) -{ - /* - Create and open an instance of our Task object. I've overridden the - open() method to make it look more like other ACE objects. - */ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Give the threads a moment to open. This isn't really necessary but if we - don't we find that all of our blocks are constructed and enqueued before - any of the threads get created. Basically, the sleep() makes the output - look more interesting. - */ - ACE_OS::sleep (ACE_Time_Value (1)); - - int i; - for (i = 0; i < iterations; ++i) - { - /* - Create a new message block to hold our data. Here, we ask for a block - that has 128 bytes of data space. - */ - Block *message = new Block (128); - - /* - Grab the "write pointer". This is a pointer into the data area where we - can write our data. After writting the data you have to increment the - wr_ptr() so that subsequent writes won't clobber what you've put there. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())); - - /* - Put the message block into the queue. One of the threads in the Task - object will pick up the block and "do work" on it. - */ - if (task.putq (message) == -1) - { - break; - } - } - - /* - Once we're done, we have to signal the Task objects to shut down. There - are several choices including: - Send a message of zero length - Send a - message with a special content I don't like these choices because they're - likely to interfere with application logic. Instead, I use the message - type feature to send a message of type "hangup". The default type is - MB_DATA, so when the tasks get a MB_HANGUP type, they know to go away. - */ - Block *message = new Block (); - message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - /* - Wait for the threads in our task object to go away. - */ - task.wait (); - - return(0); -} - -int main (int argc, char *argv[]) -{ - /* - Set the number of iterations through our putq() loop and the number of - threads to use in our Task<> derivative. - */ - int iterations = argc > 1 ? atoi (argv[1]) : 9; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - (void)run_test(iterations,threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit(0); -} diff --git a/docs/tutorials/010/page01.html b/docs/tutorials/010/page01.html deleted file mode 100644 index 23f267b2565..00000000000 --- a/docs/tutorials/010/page01.html +++ /dev/null @@ -1,36 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -In an earlier tutorial we briefly introduced ACE_Message_Queue. In this -tutorial we'll go into a bit more detail. -<P> -ACE_Message_Queue is modeled after Unix System V IPC mechanisms. The basic -idea is that you put a block of data into one end of the Queue and take it -out of the other end. Your basic FIFO in other words. The SysV mechanism -works great for passing these blocks of data between processes on the same -host but it's a bit overkill for moving blocks between threads. You could -use a pipe, socket or similar mechanism but that still has more overhead than -we really want just for moving data between threads. Process-global memory -is a good technique but then you need a way to signal the "listening" threads. -The ACE_Message_Queue is a better approach: Create blocks of data and enqueue -them in one thread while another thread (or threads) dequeue and perform work. -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/010/page02.html b/docs/tutorials/010/page02.html deleted file mode 100644 index 29d61e61aec..00000000000 --- a/docs/tutorials/010/page02.html +++ /dev/null @@ -1,132 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -We'll look first at <A HREF="message_queue.cpp">main()</A>. -<P> - -<HR WIDTH="100%"> -<PRE> -/* - To illustrate the ACE_Message_Queue, we use a derivative of ACE_Task<>. We - also derive from ACE_Message_Block to show that we don't have memory leaks. - */ -#include "task.h" -#include "block.h" - -int run_test( int iterations, int threads ) -{ - /* - Create and open an instance of our Task object. I've overridden the - open() method to make it look more like other ACE objects. - */ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Give the threads a moment to open. This isn't really necessary but if we - don't we find that all of our blocks are constructed and enqueued before - any of the threads get created. Basically, the sleep() makes the output - look more interesting. - */ - ACE_OS::sleep (ACE_Time_Value (1)); - - int i; - for (i = 0; i < iterations; ++i) - { - /* - Create a new message block to hold our data. Here, we ask for a block - that has 128 bytes of data space. - */ - Block *message = new Block (128); - - /* - Grab the "write pointer". This is a pointer into the data area where we - can write our data. After writting the data you have to increment the - wr_ptr() so that subsequent writes won't clobber what you've put there. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())); - - /* - Put the message block into the queue. One of the threads in the Task - object will pick up the block and "do work" on it. - */ - if (task.putq (message) == -1) - { - break; - } - } - - /* - Once we're done, we have to signal the Task objects to shut down. There - are several choices including: - Send a message of zero length - Send a - message with a special content I don't like these choices because they're - likely to interfere with application logic. Instead, I use the message - type feature to send a message of type "hangup". The default type is - MB_DATA, so when the tasks get a MB_HANGUP type, they know to go away. - */ - Block *message = new Block (); - message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - /* - Wait for the threads in our task object to go away. - */ - task.wait (); - - return(0); -} - -int main (int argc, char *argv[]) -{ - /* - Set the number of iterations through our putq() loop and the number of - threads to use in our Task<> derivative. - */ - int iterations = argc > 1 ? atoi (argv[1]) : 9; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - (void)run_test(iterations,threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit(0); -} -</PRE> -<HR WIDTH="100%"> -<P> -This looks a lot like our thread-pool server and it even does some things -better. In particular, I've scoped the Task object so that it's destructor -will have a chance to get called before the application exits. -Notice how we write actual data into the message block though. In the thread-pool -server we just provided a pointer. Writting the data is actually a more correct -way of doing things since you don't get into strange pointer casting situations. -What if you want to put complex objects into the message block though? We'll do -that in the next tutorial, let's stick with the basics first. -<P> -On the next page we'll take a look at our Block object... -<P> -<HR WIDTH="100%"> - -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/010/page03.html b/docs/tutorials/010/page03.html deleted file mode 100644 index 9c35bf18a86..00000000000 --- a/docs/tutorials/010/page03.html +++ /dev/null @@ -1,65 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Our <A HREF="block.h">Block</A> object is a very simple derivative -of the ACE_Message_Block. The only reason I created it was to prove -that the message blocks to, indeed, get freed when we're done with 'em. -<P> - -<HR WIDTH="100%"> -<PRE> - -#include "ace/Message_Block.h" - -/* - This simple ACE_Message_Block derivative will inform us of it's construction - and destruction. We'll use this to assure ourselves that we don't have any - memory leaks. In a real application, of course, this isn't necessary. - */ -class Block : public ACE_Message_Block -{ -public: - Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - Block (size_t size) - : ACE_Message_Block (size) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - virtual ~ Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block dtor 0x%x\n", (void *) this)); - } -}; - -</PRE> -<HR WIDTH="100%"> -<P> -Ok, nothing really magic there. Some folks just feel a little uncomfortable -not doing an explicit <i>delete</i> on objects they've <i>new</i>'d so I -wanted to show you that the memory really does get cleaned up. -<P> -<HR WIDTH="100%"> - -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/010/page04.html b/docs/tutorials/010/page04.html deleted file mode 100644 index 1a22e793475..00000000000 --- a/docs/tutorials/010/page04.html +++ /dev/null @@ -1,84 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Our <A HREF="task.h">Task</A> object executes in one or more threads -and reads from the message queue it contains. -<P> - -<HR WIDTH="100%"> -<PRE> - -#include "ace/Task.h" - -/* - Like the thread-pool server tutorial, we'll derive from ACE_Task<>. - Our goal here is to show off the ACE_Message_Queue and the best way - to do that is to use one to pass data between threads. The easiest - way to create threads is with ACE_Task<> - */ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - /* - The constructor/destructor are simple but take care of some - necessary housekeeping. - */ - Task (void); - ~Task (void); - - /* - To make our Task<> derivative look more like other ACE objects - I've added an open() method. It will take care of activate()ing - the object. - */ - int open (int threads = 1); - - /* - Our worker method - */ - int svc (void); - - /* - All we'll do here is print a message to the user. - */ - int close (u_long flags = 0); - -protected: - /* - Just to be clever, I'll use an ACE_Barrier to cause the threads - to sync in svc() before doing any real work. - */ - ACE_Barrier *barrier_; -}; -</PRE> -<HR WIDTH="100%"> -<P> -The only thing here that we didn't see in the thread-pool server is the -ACE_Barrier. The application logic really doesn't need it but it is a -handy way to synchronize the threads at the beginning of svc(). In testing -I found that if I didn't sync svc(), the first thread to get activated would -tend to get all of the messages before the other threads came alive. -<P> -<HR WIDTH="100%"> - -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/010/page05.html b/docs/tutorials/010/page05.html deleted file mode 100644 index 653cb496cb2..00000000000 --- a/docs/tutorials/010/page05.html +++ /dev/null @@ -1,168 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Our <A HREF="task.cpp">Task</A> object definition: -<P> - -<HR WIDTH="100%"> -<PRE> - -#include "task.h" -#include "block.h" - -/* - Set our housekeeping pointer to NULL and tell the user we exist. - */ -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -/* - Take care of cleanup & tell the user we're going away. -*/ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - /* - Get our shutdown notification out of the queue and release it. - */ - ACE_Message_Block * message; - this->getq(message); - message->release(); - - delete barrier_; -} - -/* - Open the object to do work. We create the Barrier object and tell - it how many threads we'll be using. Next, we activate the Task - into the number of requested threads. -*/ -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - Tell the user we're closing and invoke the baseclass' close() to - take care of things. -*/ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -/* - Our svc() method waits for work on the queue and then processes that work. - */ -int Task::svc (void) -{ - /* - This will cause all of the threads to wait on this line until all - have invoked this method. The net result is that no thread in the - Task will get a shot at the queue until all of the threads are active. - There's no real need to do this but it's an easy intro into the use - of ACE_Barrier. - */ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %d\n", (void *) this, ACE_Thread::self ())); - - /* - Remember that get() needs a reference to a pointer. To save stack - thrashing we'll go ahead and create a pointer outside of the almost- - infinite loop. - */ - ACE_Message_Block *message; - while (1) - { - /* - Get a message from the queue. - */ - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - /* - If we got the shutdown request, we need to go away. - */ - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - /* - Forward the request to any peer threads. - */ - this->putq (message); - - /* - Leave the infinite loop so that the thread exits. - */ - break; - } - - /* - The message queue stores char* data. We use rd_ptr() to get to - the beginning of the data. - */ - const char *cp = message->rd_ptr (); - - /* - Move the rd_ptr() past the data we read. This isn't real useful - here since we won't be reading any more from the block but it's - a good habit to get into. - */ - message->rd_ptr( strlen(cp) ); - - /* - Display the block's address and data to the user. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Pretend that it takes a while to process the data. - */ - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - /* - Release the message block. Notice that we never delete a message block. - Blocks are reference counted & the release() method will take care of - the delete when there are no more references to the data. - */ - message->release (); - } - - return (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -This is all pretty straight-forward too. One gottcha we avoided was a memory leak -due to our shutdown message. Notice that svc() enqueues that block without bothering -to see if there are any more threads to dequeue it. Thats why our dtor can call getq() -without worrying about blocking infinitely: it knows the message block will be there. -<P> -<HR WIDTH="100%"> - -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page06.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/010/page06.html b/docs/tutorials/010/page06.html deleted file mode 100644 index c84e923f3f5..00000000000 --- a/docs/tutorials/010/page06.html +++ /dev/null @@ -1,64 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Since I added Block just to give us output, let's take a look at that output. - -<P> -<HR WIDTH="100%"> -<PRE> -[jcej@chiroptera 010]$./message_queue 4 2 -(8910|1024) Task ctor 0xbffff9c4 -(8910|2050) Task 0xbffff9c4 starts in thread 2050 -(8910|1025) Task 0xbffff9c4 starts in thread 1025 -(8910|1024) Block ctor 0x8052398 -(8910|1024) Block ctor 0x8052488 -(8910|1024) Block ctor 0x8052578 -(8910|1024) Block ctor 0x8052668 -(8910|1024) Block ctor 0x8052758 -(8910|1025) Block 0x8052398 contains (This is message 0.) -(8910|2050) Block 0x8052488 contains (This is message 1.) -(8910|1025) Block dtor 0x8052398 -(8910|1025) Block 0x8052578 contains (This is message 2.) -(8910|2050) Block dtor 0x8052488 -(8910|2050) Block 0x8052668 contains (This is message 3.) -(8910|1025) Block dtor 0x8052578 -(8910|1025) Task close 0xbffff9c4 -(8910|2050) Block dtor 0x8052668 -(8910|2050) Task close 0xbffff9c4 -(8910|1024) Task dtor 0xbffff9c4 -(8910|1024) Block dtor 0x8052758 -(8910|1024) Application exiting -[jcej@chiroptera 010]$ -</PRE> -<HR WIDTH="100%"> -<P> -Notice that each <i>Block ctor</i> has a corresponding <i>Block dtor</i>. -We've proven the point that all memory gets cleaned up. We also see that -both threads get to do some work and that both close as expected. -<P> -It's also worth mentioning that it's just an accident that all of the blocks -are created and enqueued before any are processed. Run the test on a multi-processor -or with more iterations and you'll see some get processed before all are created. -<P> -<HR WIDTH="100%"> - - -<CENTER>[<A HREF="..">Tutorial Index</A>][<A HREF="page07.html">Continue -This Tutorial</A>]</CENTER> -</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/010/page07.html b/docs/tutorials/010/page07.html deleted file mode 100644 index c9cdaa28ee5..00000000000 --- a/docs/tutorials/010/page07.html +++ /dev/null @@ -1,36 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 010</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 010</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing chunks of data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -That's it for Tutorial 10. There are some esoteric changes between the thread-pool server -and this application but it's basically the same. In the next tutorial I'll modify this just -a bit to move non-trivial data through the queue. -<P> - -<UL> -<LI><A HREF="Makefile">Makefile</A> -<LI><A HREF="block.h">block.h</A> -<LI><A HREF="message_queue.cpp">message_queue.cpp</A> -<LI><A HREF="task.cpp">task.cpp</A> -<LI><A HREF="task.h">task.h</A> -</UL> -<HR WIDTH="100%"> - - -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> - diff --git a/docs/tutorials/010/task.cpp b/docs/tutorials/010/task.cpp deleted file mode 100644 index 84f70cae0ee..00000000000 --- a/docs/tutorials/010/task.cpp +++ /dev/null @@ -1,134 +0,0 @@ - -// $Id$ - -#include "task.h" -#include "block.h" - -/* - Set our housekeeping pointer to NULL and tell the user we exist. - */ -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -/* - Take care of cleanup & tell the user we're going away. -*/ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - /* - Get our shutdown notification out of the queue and release it. - */ - ACE_Message_Block * message; - this->getq(message); - message->release(); - - delete barrier_; -} - -/* - Open the object to do work. We create the Barrier object and tell - it how many threads we'll be using. Next, we activate the Task - into the number of requested threads. -*/ -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - Tell the user we're closing and invoke the baseclass' close() to - take care of things. -*/ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -/* - Our svc() method waits for work on the queue and then processes that work. - */ -int Task::svc (void) -{ - /* - This will cause all of the threads to wait on this line until all - have invoked this method. The net result is that no thread in the - Task will get a shot at the queue until all of the threads are active. - There's no real need to do this but it's an easy intro into the use - of ACE_Barrier. - */ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %d\n", (void *) this, ACE_Thread::self ())); - - /* - Remember that get() needs a reference to a pointer. To save stack - thrashing we'll go ahead and create a pointer outside of the almost- - infinite loop. - */ - ACE_Message_Block *message; - while (1) - { - /* - Get a message from the queue. - */ - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - /* - If we got the shutdown request, we need to go away. - */ - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - /* - Forward the request to any peer threads. - */ - this->putq (message); - - /* - Leave the infinite loop so that the thread exits. - */ - break; - } - - /* - The message queue stores char* data. We use rd_ptr() to get to - the beginning of the data. - */ - const char *cp = message->rd_ptr (); - - /* - Move the rd_ptr() past the data we read. This isn't real useful - here since we won't be reading any more from the block but it's - a good habit to get into. - */ - message->rd_ptr( strlen(cp) ); - - /* - Display the block's address and data to the user. - */ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Pretend that it takes a while to process the data. - */ - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - /* - Release the message block. Notice that we never delete a message block. - Blocks are reference counted & the release() method will take care of - the delete when there are no more references to the data. - */ - message->release (); - } - - return (0); -} diff --git a/docs/tutorials/010/task.h b/docs/tutorials/010/task.h deleted file mode 100644 index 2aecb429c03..00000000000 --- a/docs/tutorials/010/task.h +++ /dev/null @@ -1,57 +0,0 @@ - -// $Id$ - -#ifndef TASK_H -#define TASK_H - -#include "ace/Task.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -/* - Like the thread-pool server tutorial, we'll derive from ACE_Task<>. - Our goal here is to show off the ACE_Message_Queue and the best way - to do that is to use one to pass data between threads. The easiest - way to create threads is with ACE_Task<> - */ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - /* - The constructor/destructor are simple but take care of some - necessary housekeeping. - */ - Task (void); - ~Task (void); - - /* - To make our Task<> derivative look more like other ACE objects - I've added an open() method. It will take care of activate()ing - the object. - */ - int open (int threads = 1); - - /* - Our worker method - */ - int svc (void); - - /* - All we'll do here is print a message to the user. - */ - int close (u_long flags = 0); - -protected: - /* - Just to be clever, I'll use an ACE_Barrier to cause the threads - to sync in svc() before doing any real work. - */ - ACE_Barrier *barrier_; -}; - -#endif diff --git a/docs/tutorials/011/Makefile b/docs/tutorials/011/Makefile deleted file mode 100644 index d52722d4994..00000000000 --- a/docs/tutorials/011/Makefile +++ /dev/null @@ -1,59 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = message_queue - -FILES = -FILES += task - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES)) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../007/fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include .depend diff --git a/docs/tutorials/011/block.h b/docs/tutorials/011/block.h deleted file mode 100644 index 1ffc5cb4e9d..00000000000 --- a/docs/tutorials/011/block.h +++ /dev/null @@ -1,33 +0,0 @@ - -// $Id$ - -#ifndef BLOCK_H -#define BLOCK_H - -#include "ace/Message_Block.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -class Block : public ACE_Message_Block -{ -public: - Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - Block (size_t size) - : ACE_Message_Block (size) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block ctor 0x%x\n", (void *) this)); - } - - virtual ~ Block (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block dtor 0x%x\n", (void *) this)); - } -}; - -#endif diff --git a/docs/tutorials/011/data.h b/docs/tutorials/011/data.h deleted file mode 100644 index 998b4d009ec..00000000000 --- a/docs/tutorials/011/data.h +++ /dev/null @@ -1,60 +0,0 @@ - -// $Id$ - -#ifndef DATA_H -#define DATA_H - -class DataBase -{ -public: - DataBase (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase ctor 0x%x\n", (void *) this)); - } - virtual ~ DataBase (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase dtor 0x%x\n", (void *) this)); - } - - void who_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase instance 0x%x\n", (void *) this)); - } - - virtual void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a DataBase object\n")); - } - -}; - -class Data : public DataBase -{ -public: - Data (void) - : message_ (-1) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data ctor 0x%x\n", (void *) this)); - } - - Data (int message) - : message_ (message) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data ctor 0x%x for message %d\n", (void *) this, message_)); - } - virtual ~ Data (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data dtor 0x%x\n", (void *) this)); - } - - void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Data object for message %d\n", message_)); - } - -protected: - int message_; - -}; - -#endif diff --git a/docs/tutorials/011/message_queue.cpp b/docs/tutorials/011/message_queue.cpp deleted file mode 100644 index 533ecec2f37..00000000000 --- a/docs/tutorials/011/message_queue.cpp +++ /dev/null @@ -1,79 +0,0 @@ - -// $Id$ - -/* - Most of this is the same as the previous tutorial, so I'll just point out - the differences. - */ -#include "task.h" -#include "block.h" -#include "data.h" - -int run_test (int iterations, int threads) -{ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - -ACE_OS::sleep (ACE_Time_Value (1)); - - int i; - for (i = 0; i < iterations; ++i) - { - /* - Construct a Data object that we'll put into the Queue. - */ - Data data (i); - - /* - Create a block large enough for our Data object as well as a text - message. - */ - Block *message = new Block (sizeof (data) + 128); - - /* - As before, put a text message into the block. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())); - - *(message->wr_ptr ()) = 0; // Null-terminate the string we just wrote - - message->wr_ptr (1); // Move beyond the NULL - - /* - To copy arbitrary data into a message block, we use the copy() method. - Since it wants a 'const char*', we have to cast our Data pointer. - */ - message->copy ((const char *) &data, sizeof (data)); - message->wr_ptr (sizeof (data)); - - if (task.putq (message) == -1) - { - break; - } - } - - Block *message = new Block (); -message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - task.wait (); - - return (0); -} - -int main (int argc, char *argv[]) -{ - int iterations = argc > 1 ? atoi (argv[1]) : 4; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - (void) run_test (iterations, threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} diff --git a/docs/tutorials/011/page01.html b/docs/tutorials/011/page01.html deleted file mode 100644 index bb61f2dbe34..00000000000 --- a/docs/tutorials/011/page01.html +++ /dev/null @@ -1,30 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -In the previous tutorial we learned how to put text into a message queue. -While that may be useful, it isn't very exciting or realistic. In most -cases you'll need to move complex data structures between your threads. -<P> -In this tutorial I'll expand the previous by moving not only a text string -but also a more complex object. In the next tutorial I'll change things -again so that we move the complex object a bit more efficiently. -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/011/page02.html b/docs/tutorials/011/page02.html deleted file mode 100644 index 3423236c2ac..00000000000 --- a/docs/tutorials/011/page02.html +++ /dev/null @@ -1,111 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -We'll look first at <A HREF="message_queue.cpp">main()</A>. A large part of this is -the same as before, so I've only commented the changes. -<P> - -<HR WIDTH="100%"> -<P> -<PRE> -#include "task.h" -#include "block.h" -#include "data.h" - -int run_test (int iterations, int threads) -{ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - ACE_OS::sleep (ACE_Time_Value (1)); - - int i; - for (i = 0; i < iterations; ++i) - { - /* - Construct a Data object that we'll put into the Queue. - */ - Data data (i); - - /* - Create a block large enough for our Data object as well - as a text message. - */ - Block *message = new Block (sizeof (data) + 128); - - /* - As before, put a text message into the block. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())); - - *(message->wr_ptr()) = 0; // Null-terminate the string we just wrote - message->wr_ptr(1); // Move beyond the NULL - - /* - To copy arbitrary data into a message block, we use the copy() method. - Since it wants a 'const char*', we have to cast our Data pointer. - */ - message->copy ((const char *) &data, sizeof (data)); - message->wr_ptr (sizeof (data)); - - if (task.putq (message) == -1) - { - break; - } - } - - Block *message = new Block (); - message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - task.wait (); - - return (0); -} - -int main (int argc, char *argv[]) -{ - int iterations = argc > 1 ? atoi (argv[1]) : 4; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - (void) run_test (iterations, threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} -</PRE> - -<HR WIDTH="100%"> -<P> -The new trick here is the use of copy() to copy our abstract data object -into the message block memory. Notice that it's OK to let the Data object -go out of scope at that point since we've got a separate copy. If you've -got something with a non-trivial ctor/dtor then this won't work. We'll address -that in the next tutorial. -<P> -<HR WIDTH="100%"> - -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/011/page03.html b/docs/tutorials/011/page03.html deleted file mode 100644 index 690bf01ce0c..00000000000 --- a/docs/tutorials/011/page03.html +++ /dev/null @@ -1,136 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Our <A HREF="task.cpp">Task</A> object definition. As with message_queue.cpp, -I've only commented the changes. -<P> - -<HR WIDTH="100%"> -<PRE> - -#include "task.h" -#include "block.h" -#include "data.h" - -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - ACE_Message_Block *message; - this->getq (message); - message->release (); - - delete barrier_; -} - -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -int Task::svc (void) -{ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %d\n", (void *) this, ACE_Thread::self ())); - - ACE_Message_Block *message; - while (1) - { - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - this->putq (message); - - break; - } - - const char *cp = message->rd_ptr (); - message->rd_ptr (strlen (cp) + 1); // Don't forget to skip the NULL we - // inserted - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Create a Data object into which we can extract the message block - contents. - */ - Data data; - /* - Use the rd_ptr() to access the message block data. Note that we've - already moved it past the text string in the block. - */ - ACE_OS::memmove ((char *) &data, message->rd_ptr (), sizeof (data)); - message->rd_ptr (sizeof (data)); // Move the rd_ptr() beyond the data. - - /* - Invoke a couple of method calls on the object we constructed. - */ - data.who_am_i (); - data.what_am_i (); - - /* - An alternate approach: - - Data * data; - data = (Data *)message->rd_ptr(); - data->who_am_i(); - data->what_am_i(); - message->rd_ptr(sizeof(Data)); - - Even though this cuts down on the number of copies & constructions, I'm - not real fond of it. You can get into trouble in a hurry by treating - memory blocks as multiple data types... - */ - - - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - message->release (); - } - - return (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -Notice how we had to create a temporary Data object to copy the stuff out -of the message block? Again, if there were non-trivial ctor/dtors involved -then this wouldn't work at all. -<P> -<HR WIDTH="100%"> - -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/011/page04.html b/docs/tutorials/011/page04.html deleted file mode 100644 index 9e701d4216f..00000000000 --- a/docs/tutorials/011/page04.html +++ /dev/null @@ -1,91 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Before we go further, let's look at this <A HREF="data.h">Data</A> object -that's causing all the fuss. - -<P> -<HR WIDTH="100%"> -<PRE> - -class DataBase -{ -public: - DataBase (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase ctor 0x%x\n", (void *) this)); - } - virtual ~ DataBase (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase dtor 0x%x\n", (void *) this)); - } - - void who_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) DataBase instance 0x%x\n", (void *) this)); - } - - virtual void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a DataBase object\n")); - } - -}; - -class Data : public DataBase -{ -public: - Data (void) - : message_ (-1) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data ctor 0x%x\n", (void *) this)); - } - - Data (int message) - : message_ (message) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data ctor 0x%x for message %d\n", (void *) this, message_)); - } - virtual ~ Data (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data dtor 0x%x\n", (void *) this)); - } - - void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Data object for message %d\n", message_)); - } - -protected: - int message_; - -}; - -</PRE> -<HR WIDTH="100%"> -<P> -Ok, no mysterious magic on this one. Just a simple object and derivative -that report their existence. -<P> -<HR WIDTH="100%"> - - -<CENTER>[<A HREF="..">Tutorial Index</A>][<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> -</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/011/page05.html b/docs/tutorials/011/page05.html deleted file mode 100644 index 813050f8a1e..00000000000 --- a/docs/tutorials/011/page05.html +++ /dev/null @@ -1,99 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> - -Let's take a look at this new program's output: - -<P> -<HR WIDTH="100%"> -<PRE> -[jcej@chiroptera 011]$./message_queue 4 2 -(12108|1024) Task ctor 0xbffff9c8 -(12108|2050) Task 0xbffff9c8 starts in thread 2050 -(12108|1025) Task 0xbffff9c8 starts in thread 1025 -(12108|1024) DataBase ctor 0xbffff9c0 -(12108|1024) Data ctor 0xbffff9c0 for message 0 -(12108|1024) Block ctor 0x8052d08 -(12108|1024) Data dtor 0xbffff9c0 -(12108|1024) DataBase dtor 0xbffff9c0 -(12108|1024) DataBase ctor 0xbffff9c0 -(12108|1024) Data ctor 0xbffff9c0 for message 1 -(12108|1024) Block ctor 0x8052e00 -(12108|1024) Data dtor 0xbffff9c0 -(12108|1024) DataBase dtor 0xbffff9c0 -(12108|1024) DataBase ctor 0xbffff9c0 -(12108|1024) Data ctor 0xbffff9c0 for message 2 -(12108|1024) Block ctor 0x8052ef8 -(12108|1024) Data dtor 0xbffff9c0 -(12108|1024) DataBase dtor 0xbffff9c0 -(12108|1024) DataBase ctor 0xbffff9c0 -(12108|1024) Data ctor 0xbffff9c0 for message 3 -(12108|1024) Block ctor 0x8052ff0 -(12108|1024) Data dtor 0xbffff9c0 -(12108|1024) DataBase dtor 0xbffff9c0 -(12108|1024) Block ctor 0x80530e8 -(12108|1025) Block 0x8052d08 contains (This is message 0.) -(12108|1025) DataBase ctor 0xbf9ffe20 -(12108|1025) Data ctor 0xbf9ffe20 -(12108|1025) DataBase instance 0xbf9ffe20 -(12108|1025) I am a Data object for message 0 -(12108|1025) Block dtor 0x8052d08 -(12108|1025) Data dtor 0xbf9ffe20 -(12108|1025) DataBase dtor 0xbf9ffe20 -(12108|1025) Block 0x8052e00 contains (This is message 1.) -(12108|1025) DataBase ctor 0xbf9ffe20 -(12108|1025) Data ctor 0xbf9ffe20 -(12108|1025) DataBase instance 0xbf9ffe20 -(12108|1025) I am a Data object for message 1 -(12108|1025) Block dtor 0x8052e00 -(12108|1025) Data dtor 0xbf9ffe20 -(12108|1025) DataBase dtor 0xbf9ffe20 -(12108|1025) Block 0x8052ef8 contains (This is message 2.) -(12108|1025) DataBase ctor 0xbf9ffe20 -(12108|1025) Data ctor 0xbf9ffe20 -(12108|1025) DataBase instance 0xbf9ffe20 -(12108|1025) I am a Data object for message 2 -(12108|1025) Block dtor 0x8052ef8 -(12108|1025) Data dtor 0xbf9ffe20 -(12108|1025) DataBase dtor 0xbf9ffe20 -(12108|1025) Block 0x8052ff0 contains (This is message 3.) -(12108|1025) DataBase ctor 0xbf9ffe20 -(12108|1025) Data ctor 0xbf9ffe20 -(12108|1025) DataBase instance 0xbf9ffe20 -(12108|1025) I am a Data object for message 3 -(12108|2050) Task close 0xbffff9c8 -(12108|1025) Block dtor 0x8052ff0 -(12108|1025) Data dtor 0xbf9ffe20 -(12108|1025) DataBase dtor 0xbf9ffe20 -(12108|1025) Task close 0xbffff9c8 -(12108|1024) Task dtor 0xbffff9c8 -(12108|1024) Block dtor 0x80530e8 -(12108|1024) Application exiting -[jcej@chiroptera 011]$ -</PRE> -<HR WIDTH="100%"> -<P> -Other than being more verbose because of the Data object, this shows us -the same thing we've seen before. -<P> -<HR WIDTH="100%"> - - -<CENTER>[<A HREF="..">Tutorial Index</A>][<A HREF="page06.html">Continue -This Tutorial</A>]</CENTER> -</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/011/page06.html b/docs/tutorials/011/page06.html deleted file mode 100644 index bde7f86e04c..00000000000 --- a/docs/tutorials/011/page06.html +++ /dev/null @@ -1,38 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 011</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 011</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing non-trivial data through an ACE_Message_Queue</FONT></B></CENTER> - - -<HR WIDTH="100%"> -<P> -So, this time we stuffed an object into the message queue instead of just text -data. Each time required two object constructions (and subsequent destructions) -and two "deep" copy operations on the object. There might actually be times when -this is OK for your application but I prefer to keep those things down to a -minimum. In the next tutorial I'll show you a way to do that. -<P> - -<UL> -<LI><A HREF="Makefile">Makefile</A> -<LI><A HREF="block.h">block.h</A> -<LI><A HREF="data.h">data.h</A> -<LI><A HREF="message_queue.cpp">message_queue.cpp</A> -<LI><A HREF="task.cpp">task.cpp</A> -<LI><A HREF="task.h">task.h</A> -</UL> -<HR WIDTH="100%"> - - -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> - diff --git a/docs/tutorials/011/task.cpp b/docs/tutorials/011/task.cpp deleted file mode 100644 index a7215191481..00000000000 --- a/docs/tutorials/011/task.cpp +++ /dev/null @@ -1,102 +0,0 @@ - -// $Id$ - -#include "task.h" -#include "block.h" -#include "data.h" - -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - ACE_Message_Block *message; - this->getq (message); - message->release (); - - delete barrier_; -} - -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -int Task::svc (void) -{ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %d\n", (void *) this, ACE_Thread::self ())); - - ACE_Message_Block *message; - while (1) - { - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - this->putq (message); - - break; - } - - const char *cp = message->rd_ptr (); - message->rd_ptr (strlen (cp) + 1); // Don't forget to skip the NULL we - // inserted - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Create a Data object into which we can extract the message block - contents. - */ - Data data; - /* - Use the rd_ptr() to access the message block data. Note that we've - already moved it past the text string in the block. - */ - ACE_OS::memmove ((char *) &data, message->rd_ptr (), sizeof (data)); - message->rd_ptr (sizeof (data)); // Move the rd_ptr() beyond the data. - - /* - Invoke a couple of method calls on the object we constructed. - */ - data.who_am_i (); - data.what_am_i (); - - /* - An alternate approach: - - Data * data; - data = (Data *)message->rd_ptr(); - data->who_am_i(); - data->what_am_i(); - message->rd_ptr(sizeof(Data)); - - Even though this cuts down on the number of copies & constructions, I'm - not real fond of it. You can get into trouble in a hurry by treating - memory blocks as multiple data types... - */ - - - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - message->release (); - } - - return (0); -} diff --git a/docs/tutorials/011/task.h b/docs/tutorials/011/task.h deleted file mode 100644 index 8646fac1a7c..00000000000 --- a/docs/tutorials/011/task.h +++ /dev/null @@ -1,32 +0,0 @@ - -// $Id$ - -#ifndef TASK_H -#define TASK_H - -#include "ace/Task.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - Task (void); - ~Task (void); - - int open (int threads = 1); - - int svc (void); - - int close (u_long flags = 0); - -protected: - ACE_Barrier * barrier_; -}; - -#endif diff --git a/docs/tutorials/012/Makefile b/docs/tutorials/012/Makefile deleted file mode 100644 index d52722d4994..00000000000 --- a/docs/tutorials/012/Makefile +++ /dev/null @@ -1,59 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = message_queue - -FILES = -FILES += task - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES)) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../007/fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include .depend diff --git a/docs/tutorials/012/data.h b/docs/tutorials/012/data.h deleted file mode 100644 index 54e8e55e87c..00000000000 --- a/docs/tutorials/012/data.h +++ /dev/null @@ -1,132 +0,0 @@ - -// $Id$ - -#ifndef DATA_H -#define DATA_H - -#include "ace/Message_Block.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -/* - We'll start by defining a basic unit of work that can be put into - the message queue. The threads in the pool will expect to find one - of these in each message block and will invoke a method or two. -*/ -class Unit_Of_Work -{ -public: - Unit_Of_Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work ctor 0x%x\n", (void *) this)); - } - virtual ~ Unit_Of_Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work dtor 0x%x\n", (void *) this)); - } - - void who_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work instance 0x%x\n", (void *) this)); - } - - virtual void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Unit_Of_Work object\n")); - } - -}; - -/* - Now, we specialize the Unit_Of_Work object to do something - different. By overriding the virtual methods, we can do whatever - "real work" is needed but the thread pool doesn't have to know the specifics. -*/ -class Work : public Unit_Of_Work -{ -public: - Work (void) - : message_ (-1) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work ctor 0x%x\n", (void *) this)); - } - - Work (int message) - : message_ (message) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work ctor 0x%x for message %d\n", (void *) this, message_)); - } - virtual ~ Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work dtor 0x%x\n", (void *) this)); - } - - void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Work object for message %d\n", message_)); - } - -protected: - int message_; - -}; - -/* - We derive a Message_Block from ACE_Message_Block and teach it about - our Unit_Of_Work object. When our task's svc() method pulls a block - out of the queue, it can then invoke the virtual methods of the work - object safely. In this implementation we've also retained the - original ACE_Message_Block functionallity so that we can use the - underlying ACE_Data_Block objects to store data other than our - Unit_Of_Work. -*/ -class Message_Block : public ACE_Message_Block -{ -public: - typedef ACE_Message_Block inherited; - - /* - Construct our underlying ACE_Message_Block with the requested - data size and initialize our Unit_Of_Work pointer with the - given object instance. Note that this Message_Block instance - now assumes ownership of the Unit_Of_Work and will delete it - when the Message_Block is deleted. - */ - Message_Block( size_t size, Unit_Of_Work * _data ) - : inherited(size), data_(_data) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block ctor 0x%x for 0x%x\n", (void *) this, data_)); - } - - ~Message_Block(void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block dtor 0x%x for 0x%x\n", (void *) this, data_)); - delete data_; - } - - /* - Return the Unit_Of_Work so that the task can invoke methods on - it. - */ - Unit_Of_Work * data(void) - { - return this->data_; - } - -protected: - Unit_Of_Work * data_; - - /* - Disallow these very dangerous operations. - If we were to copy a Message_Block object then the data_ - pointer would get copied and we would eventually end up - deleting the same object multiple times! That's not good. By - preventing the copy, we can avoid this. - */ - Message_Block &operator= (const Message_Block &); - Message_Block (const Message_Block &); -}; - -#endif diff --git a/docs/tutorials/012/message_queue.cpp b/docs/tutorials/012/message_queue.cpp deleted file mode 100644 index b4fee1be01b..00000000000 --- a/docs/tutorials/012/message_queue.cpp +++ /dev/null @@ -1,96 +0,0 @@ - -// $Id$ - -#include "data.h" -#include "task.h" - -/* - I want to be sure that our Task object gets destructed correctly, so - I'll do most of the application 'work' in run_test() instead of - main() -*/ -int run_test (int iterations, int threads) -{ - /* - Create the Task which is our thread pool for doing work - */ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Give the Task a chance to enter it's svc() method. This isn't - really necessary and you probably wouldn't do it in a real - application but it makes the output more interesting. - */ - ACE_OS::sleep (ACE_Time_Value (1)); - - for (int i = 0; i < iterations; ++i) - { - /* - Construct a Work object that we'll put into the Queue. Give it - the iteration number so that it can identify itself in the output. - */ - Work * data = new Work(i); - - /* - Create a block that contains our Work object but also has - enough room for a text message. - */ - Message_Block *message = new Message_Block (128, data); - - /* - As before, put a text message into the block. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())+1); - - /* - Add the work to our thread pool - */ - if (task.putq (message) == -1) - { - break; - } - } - - /* - Insert a HANGUP message block to tell the thread pool to shut - itself down. - */ - Message_Block *message = new Message_Block (0,0); - message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - /* - Wait for the all threads of the Task to exit. It is rather rude - to let the Task go out of scope without doing this first. - */ - task.wait (); - - return (0); -} - -int main (int argc, char *argv[]) -{ - /* - Give the user a chance to override the default number of - iterations and pool threads. - */ - int iterations = argc > 1 ? atoi (argv[1]) : 4; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - /* - Use the function above to do the actual test. As I said, this - lets us see the Task go out of scope and destruct before our - "exiting" message below. - */ - (void) run_test (iterations, threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} diff --git a/docs/tutorials/012/page01.html b/docs/tutorials/012/page01.html deleted file mode 100644 index a799f932016..00000000000 --- a/docs/tutorials/012/page01.html +++ /dev/null @@ -1,32 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -Last time around we put an object into a message queue by using the -copy() method to create a duplicate of the object. That's probably OK -for simple objects that aren't very large. However, if you have an -object that contains pointers or tons of data then that approach is -going to cause problems. -<P> -What we'll do in this tutorial is specialize the ACE_Message_Block -object so that it can carry our data more efficiently. As you'll see, -this isn't very difficult at all. -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/012/page02.html b/docs/tutorials/012/page02.html deleted file mode 100644 index 9647dd84a83..00000000000 --- a/docs/tutorials/012/page02.html +++ /dev/null @@ -1,104 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -We normally start by looking at main() and work our way out from -there. This time, I want to start by showing you the ACE_Message_Block -derivative but before that, I have to introduce you to the Work object -and it's baseclass Unit_Of_Work -<P> -<HR WIDTH="100%"> -<PRE> - -/* - We'll start by defining a basic unit of work that can be put into - the message queue. The threads in the pool will expect to find one - of these in each message block and will invoke a method or two. -*/ -class Unit_Of_Work -{ -public: - Unit_Of_Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work ctor 0x%x\n", (void *) this)); - } - virtual ~ Unit_Of_Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work dtor 0x%x\n", (void *) this)); - } - - void who_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Unit_Of_Work instance 0x%x\n", (void *) this)); - } - - virtual void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Unit_Of_Work object\n")); - } - -}; - -/* - Now, we specialize the Unit_Of_Work object to do something - different. By overriding the virtual method, we can do whatever - "real work" is needed but the thread pool doesn't have to know the specifics. -*/ -class Work : public Unit_Of_Work -{ -public: - Work (void) - : message_ (-1) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work ctor 0x%x\n", (void *) this)); - } - - Work (int message) - : message_ (message) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work ctor 0x%x for message %d\n", (void *) this, message_)); - } - virtual ~ Work (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Work dtor 0x%x\n", (void *) this)); - } - - void what_am_i (void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) I am a Work object for message %d\n", message_)); - } - -protected: - int message_; - -}; -</PRE> -<HR WIDTH="100%"> -<P> -This is basically the same as the <i>DataBase</i> in the previous -tutorial but I've changed the name to be more generic. The feeling is -that a <i>Data</i> object would be a C struct but an <i>Work</i> -object would be a class with methods. -<P> -Now that you know what we'll be putting into the queue, lets go to the -next page where I specialize the ACE_Message_Block. -<P> -<HR WIDTH="100%"> -<P> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/012/page03.html b/docs/tutorials/012/page03.html deleted file mode 100644 index c0a94ee30a1..00000000000 --- a/docs/tutorials/012/page03.html +++ /dev/null @@ -1,100 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -In the previous tutorial we moved our complex data into the queue by -copy()ing it directly into the message block's data area. I hope that -most readers got a queasy feeling when I did that. It just isn't a -good idea... -<P> -A better idea would be to teach the message queue about our data types -(or at least a baseclass) so that it can more efficiently handle things: -<P> -<HR WIDTH="100%"> -<PRE> -/* - We derive a Message_Block from ACE_Message_Block and teach it about - our Unit_Of_Work object. When our task's svc() method pulls a block - out of the queue, it can then invoke the virtual methods of the work - object safely. In this implementation we've also retained the - original ACE_Message_Block functionallity so that we can use the - underlying ACE_Data_Block objects to store data other than our - Unit_Of_Work. -*/ -class Message_Block : public ACE_Message_Block -{ -public: - typedef ACE_Message_Block inherited; - - /* - Construct our underlying ACE_Message_Block with the requested - data size and initialize our Unit_Of_Work pointer with the - given object instance. Note that this Message_Block instance - now assumes ownership of the Unit_Of_Work and will delete it - when the Message_Block is deleted. - */ - Message_Block( size_t size, Unit_Of_Work * _data ) - : inherited(size), data_(_data) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block ctor 0x%x for 0x%x\n", (void *) this, data_)); - } - - ~Message_Block(void) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Message_Block dtor 0x%x for 0x%x\n", (void *) this, data_)); - delete data_; - } - - /* - Return the Unit_Of_Work so that the task can invoke methods on - it. - */ - Unit_Of_Work * data(void) - { - return this->data_; - } - -protected: - Unit_Of_Work * data_; - - /* - Disallow these very dangerous operations. - If we were to copy a Message_Block object then the data_ - pointer would get copied and we would eventually end up - deleting the same object multiple times! That's not good. By - preventing the copy, we can avoid this. - */ - Message_Block &operator= (const Message_Block &); - Message_Block (const Message_Block &); -}; -</PRE> -<HR WIDTH="100%"> -<P> -Ok, this looks pretty good. We just construct our specialized -Message_Block instead of the generic ACE_Message_Block and let it -carry our data along. When our application is done with the message -block and release()es it, we know that our work object will also be -taken care of. -<P> -Let's now go to main() and see what we had to change there to use this -specialization. -<P> -<HR WIDTH="100%"> -<P> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/012/page04.html b/docs/tutorials/012/page04.html deleted file mode 100644 index 34e51c643ee..00000000000 --- a/docs/tutorials/012/page04.html +++ /dev/null @@ -1,124 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -Ok, finally we get to main(). Sorry for the diversion but it was -important to lay some of that groundwork before getting here. -<P> -<HR WIDTH="100%"> -<PRE> -/* - I want to be sure that our Task object gets destructed correctly, so - I'll do most of the application 'work' in run_test() instead of - main() -*/ -int run_test (int iterations, int threads) -{ - /* - Create the Task which is our thread pool for doing work - */ - Task task; - - if (task.open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - /* - Give the Task a chance to enter it's svc() method. This isn't - really necessary and you probably wouldn't do it in a real - application but it makes the output more interesting. - */ - ACE_OS::sleep (ACE_Time_Value (1)); - - for (int i = 0; i < iterations; ++i) - { - /* - Construct a Work object that we'll put into the Queue. Give it - the iteration number so that it can identify itself in the output. - */ - Work * data = new Work(i); - - /* - Create a block that contains our Work object but also has - enough room for a text message. - */ - Message_Block *message = new Message_Block (128, data); - - /* - As before, put a text message into the block. - */ - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())+1); - - /* - Add the work to our thread pool - */ - if (task.putq (message) == -1) - { - break; - } - } - - /* - Insert a HANGUP message block to tell the thread pool to shut - itself down. - */ - Message_Block *message = new Message_Block (0,0); - message->msg_type (ACE_Message_Block::MB_HANGUP); - task.putq (message); - - /* - Wait for the all threads of the Task to exit. It is rather rude - to let the Task go out of scope without doing this first. - */ - task.wait (); - - return (0); -} - -int main (int argc, char *argv[]) -{ - /* - Give the user a chance to override the default number of - iterations and pool threads. - */ - int iterations = argc > 1 ? atoi (argv[1]) : 4; - int threads = argc > 2 ? atoi (argv[2]) : 2; - - /* - Use the function above to do the actual test. As I said, this - lets us see the Task go out of scope and destruct before our - "exiting" message below. - */ - (void) run_test (iterations, threads); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -That certainly looks cleaner than the previous approach! If you -blink, you'll miss the part where the Work object goes into the Queue. -<P> -<HR WIDTH="100%"> -<P> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/012/page05.html b/docs/tutorials/012/page05.html deleted file mode 100644 index 89c3e6f8da0..00000000000 --- a/docs/tutorials/012/page05.html +++ /dev/null @@ -1,211 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -The Task is the only object we've not been through yet. I'll go ahead -and show both the header and cpp on this one page since the header -isn't very large. -<P> -<HR WIDTH="100%"> -<PRE> - -/* - This is our basic thread-pool Task. We have a choice of pool size - on the open() and the usual svc() and close() methods. - - A new addition is the ACE_Barrier object. This will allow the - synchronization of our svc() methods so that they all start at the - "same" time. The normal case may allow one thread to start working - earlier than others. There's no real harm in it but you can get - better "work by thread" statistics if they start out together. -*/ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - Task (void); - ~Task (void); - - int open (int threads = 1); - - int svc (void); - - int close (u_long flags = 0); - -protected: - ACE_Barrier * barrier_; -}; -</PRE> -<HR WIDTH="50%"> -<PRE> -/* - Boring default constructor. Be sure our barrier_ is initialized in - case we get destructed before opened. -*/ -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -/* - You'll see in the svc() method that when we get a shutdown request, - we always putq() it back into our message queue. The last thread in - the pool will do this also and result in there always being one - shutdown request left in the queue when we get here. Just to be - polite, we'll go ahead and get that message and release it. - - We also delete the barrier_ object we used to synch the svc() - methods. -*/ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - ACE_Message_Block *message; - this->getq (message); - message->release (); - - delete barrier_; -} - -/* - The ACE_Barrier needs to know how many threads it will be working - for. For that reason, we have to put off it's construction until we - get here. We then pass the thread count through to our base class' - activate(). -*/ -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - We don't really do anything here but I wanted to provide a message - in the output. -*/ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -/* - Now the svc() method where everything interesting happens. -*/ -int Task::svc (void) -{ - /* - All of the threads will block here until the last thread - arrives. They will all then be free to begin doing work. - */ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %u\n", (void *) this, ACE_Thread::self ())); - - // Where we getq() the message - ACE_Message_Block *message; - // What we really put into the queue is a Message_Block, so we'll - // cast the 'message' to 'message_block' after getting it. I'm - // going through some extra steps here just to be explicit - Message_Block * message_block; - // The baseclass of the work object we put into the queue. Notice - // that we can use this and not bother with the Work object at all. - Unit_Of_Work * unit_of_work; - - while (1) - { - // Get the message... - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - // Is it a shutdown request? - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - // Send the shutdown to all of our pool peers - this->putq (message); - break; - } - - // Cast the pointer to our specialized Message_Block. We could - // have done this at the getq() call but I wanted to be explicit - // about what we're doing here - message_block = (Message_Block*)message; - - /* - Since we left alone the ACE_Data_Block used by the - Message_Block we have chosen to use it to send arbitrary data - as well. - */ - const char *cp = message_block->rd_ptr (); - // Don't forget to skip the NULL we inserted - message_block->rd_ptr (strlen (cp) + 1); - - /* - Get the Unit_Of_Work pointer out of our specialized - Message_Block. Since the methods of interest are virtual, we - don't have to know what kind of work we're to do. - */ - unit_of_work = message_block->data(); - - /* - Invoke a couple of method calls on the object we constructed. - */ - unit_of_work->who_am_i (); - unit_of_work->what_am_i (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Pretend that the work takes a little time to process. This - prevents one thread from getting all of the action. In a real - system you wouldn't need to do this since the work really - would take time to complete. - */ - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - /* - Release the message block and allow the unit of work to also go - away. - */ - message->release (); - } - - return (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -Like main() this is actually simpler than the previous tutorial. It's -much cleaner to carry around a pointer to the object we're working -with than to try copying data. -<P> -The only complication is the new ACE_Barrier. It's a pretty simple -object that makes it easy for you to synch threads in this way. You -could do some fancy tricks with mutexes, counters & semaphores but why -bother when the Barrier already exists. -<P> -<HR WIDTH="100%"> -<P> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page06.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/012/page06.html b/docs/tutorials/012/page06.html deleted file mode 100644 index f3f858d14c1..00000000000 --- a/docs/tutorials/012/page06.html +++ /dev/null @@ -1,33 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 012</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 012</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Passing classes through ACE_Message_Queue</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -Once again, we come to the end of a tutorial. By creating a simple -specialization of ACE_Message_Block, we've been able to remove a lot -of complexity and erorr potential from our previous implementation. -<UL> -<LI><A HREF="Makefile">Makefile</A> -<LI><A HREF="message_queue.cpp">message_queue.cpp</A> -<LI><A HREF="data.h">data.h</A> -<LI><A HREF="task.h">task.h</A> -<LI><A HREF="task.cpp">task.cpp</A> -</UL> -<P> -<HR WIDTH="100%"> -<P> -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/012/task.cpp b/docs/tutorials/012/task.cpp deleted file mode 100644 index 5c7a382db16..00000000000 --- a/docs/tutorials/012/task.cpp +++ /dev/null @@ -1,144 +0,0 @@ - -// $Id$ - -#include "task.h" -#include "data.h" - -/* - Boring default constructor. Be sure our barrier_ is initialized in - case we get destructed before opened. -*/ -Task::Task (void) -: barrier_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); -} - -/* - You'll see in the svc() method that when we get a shutdown request, - we always putq() it back into our message queue. The last thread in - the pool will do this also and result in there always being one - shutdown request left in the queue when we get here. Just to be - polite, we'll go ahead and get that message and release it. - - We also delete the barrier_ object we used to synch the svc() - methods. -*/ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - ACE_Message_Block *message; - this->getq (message); - message->release (); - - delete barrier_; -} - -/* - The ACE_Barrier needs to know how many threads it will be working - for. For that reason, we have to put off it's construction until we - get here. We then pass the thread count through to our base class' - activate(). -*/ -int Task::open (int threads) -{ - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - We don't really do anything here but I wanted to provide a message - in the output. -*/ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - return inherited::close (flags); -} - -/* - Now the svc() method where everything interesting happens. -*/ -int Task::svc (void) -{ - /* - All of the threads will block here until the last thread - arrives. They will all then be free to begin doing work. - */ - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %u\n", (void *) this, ACE_Thread::self ())); - - // Where we getq() the message - ACE_Message_Block *message; - // What we really put into the queue is a Message_Block, so we'll - // cast the 'message' to 'message_block' after getting it. I'm - // going through some extra steps here just to be explicit - Message_Block * message_block; - // The baseclass of the work object we put into the queue. Notice - // that we can use this and not bother with the Work object at all. - Unit_Of_Work * unit_of_work; - - while (1) - { - // Get the message... - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - // Is it a shutdown request? - if (message->msg_type () == ACE_Message_Block::MB_HANGUP) - { - // Send the shutdown to all of our pool peers - this->putq (message); - break; - } - - // Cast the pointer to our specialized Message_Block. We could - // have done this at the getq() call but I wanted to be explicit - // about what we're doing here - message_block = (Message_Block*)message; - - /* - Since we left alone the ACE_Data_Block used by the - Message_Block we have chosen to use it to send arbitrary data - as well. - */ - const char *cp = message_block->rd_ptr (); - // Don't forget to skip the NULL we inserted - message_block->rd_ptr (strlen (cp) + 1); - - /* - Get the Unit_Of_Work pointer out of our specialized - Message_Block. Since the methods of interest are virtual, we - don't have to know what kind of work we're to do. - */ - unit_of_work = message_block->data(); - - /* - Invoke a couple of method calls on the object we constructed. - */ - unit_of_work->who_am_i (); - unit_of_work->what_am_i (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Block 0x%x contains (%s)\n", (void *) message, cp)); - - /* - Pretend that the work takes a little time to process. This - prevents one thread from getting all of the action. In a real - system you wouldn't need to do this since the work really - would take time to complete. - */ - ACE_OS::sleep (ACE_Time_Value (0, 5000)); - - /* - Release the message block and allow the unit of work to also go - away. - */ - message->release (); - } - - return (0); -} diff --git a/docs/tutorials/012/task.h b/docs/tutorials/012/task.h deleted file mode 100644 index 877ac98ede5..00000000000 --- a/docs/tutorials/012/task.h +++ /dev/null @@ -1,42 +0,0 @@ - -// $Id$ - -#ifndef TASK_H -#define TASK_H - -#include "ace/Task.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -/* - This is our basic thread-pool Task. We have a choice of pool size - on the open() and the usual svc() and close() methods. - - A new addition is the ACE_Barrier object. This will allow the - synchronization of our svc() methods so that they all start at the - "same" time. The normal case may allow one thread to start working - earlier than others. There's no real harm in it but you can get - better "work by thread" statistics if they start out together. -*/ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - Task (void); - ~Task (void); - - int open (int threads = 1); - - int svc (void); - - int close (u_long flags = 0); - -protected: - ACE_Barrier * barrier_; -}; - -#endif diff --git a/docs/tutorials/013/Makefile b/docs/tutorials/013/Makefile deleted file mode 100644 index 7e39257c5aa..00000000000 --- a/docs/tutorials/013/Makefile +++ /dev/null @@ -1,59 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = message_queue - -FILES = task block work mld - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) -SRC += $(addsuffix .cpp,$(FILES)) - -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../007/fix.Makefile - -.depend : # - touch .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include .depend diff --git a/docs/tutorials/013/block.cpp b/docs/tutorials/013/block.cpp deleted file mode 100644 index 5d997510244..00000000000 --- a/docs/tutorials/013/block.cpp +++ /dev/null @@ -1,98 +0,0 @@ - -// $Id$ - -#include "block.h" - -/* - Construct a Dat_Block to contain a unit of work. Note the careful - construction of the baseclass to set the block type and the locking - strategy. - */ -Data_Block::Data_Block (Unit_Of_Work * _data) -: inherited (0, ACE_Message_Block::MB_DATA, 0, 0, new Lock (), 0, 0) -,data_ (_data) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Data_Block ctor for 0x%x\n", (void *) this, (void *) data_)); -} - -/* - The Lock object created in the constructor is stored in the baseclass and - available through the locking_strategy() method. We can cast it's value to - our Lock object and invoke the destroy() to indicate that we want it to go - away when the lock is released. - */ -Data_Block::~Data_Block (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Data_Block dtor for 0x%x\n", (void *) this, (void *) data_)); - ((Lock *) locking_strategy ())->destroy (); - delete data_; -} - -/* - Return the data - */ -Unit_Of_Work *Data_Block::data (void) -{ - return this->data_; -} - -Data_Block:: Lock::Lock (void) -:destroy_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Lock ctor\n", (void *) this)); -} - -Data_Block:: Lock::~Lock (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Lock dtor\n", (void *) this)); -} - -/* - Set our destroy_ flag so that the next lock release will cause us to be - deleted. - */ -int Data_Block::Lock::destroy (void) -{ - ++destroy_; - return (0); -} - -/* - Mutexes have acquire() and release() methods. We've overridden the latter - so that when the object we're protecting goes away, we can make ourselves go - away after the lock is released. - */ -int Data_Block::Lock::release (void) -{ - int rval = inherited::release (); - if (destroy_) - { - delete this; - } - return rval; -} - -/* - Create an baseclass unit of work when we instantiate a hangup message. - */ -Message_Block::Message_Block (void) -:inherited (new Data_Block (new Unit_Of_Work ())) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block ctor for shutdown\n", (void *) this)); - this->msg_type (MB_HANGUP); -} - -/* - Store the unit of work in a Data_Block and initialize the baseclass with - that data. - */ -Message_Block::Message_Block (Unit_Of_Work * _data) -:inherited (new Data_Block (_data)) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block ctor for 0x%x\n", (void *) this, (void *) _data)); -} - -Message_Block::~Message_Block (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block dtor\n", (void *) this)); -} diff --git a/docs/tutorials/013/block.h b/docs/tutorials/013/block.h deleted file mode 100644 index 26604a57e4c..00000000000 --- a/docs/tutorials/013/block.h +++ /dev/null @@ -1,89 +0,0 @@ - -// $Id$ - -#ifndef BLOCK_H -#define BLOCK_H - -#include "ace/Message_Block.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "ace/Synch.h" -#include "mld.h" -#include "work.h" - -/* - In this Tutorial, we derive from ACE_Data_Block for our special data. With - the possiblilty that our Task object may forward the unit of work on to - another thread pool, we have to make sure that the data object doesn't go - out of scope unexpectedly. An ACE_Message_Block will be deleted as soon as - it's release() method is called but the ACE_Data_Blocks it uses are - reference counted and only delete when the last reference release()es the - block. We use that trait to simply our object memory management. - */ -class Data_Block : public ACE_Data_Block -{ -public: - typedef ACE_Data_Block inherited; - - // Create a data block with a unit of work to be done - Data_Block (Unit_Of_Work * _data); - - ~Data_Block (void); - - // Returns the work pointer - Unit_Of_Work *data (void); - -protected: - Unit_Of_Work * data_; - MLD; // Our memory leak detector - - // The ACE_Data_Block allows us to choose a locking strategy - // for making the reference counting thread-safe. The - // ACE_Lock_Adaptor<> template adapts the interface of a - // number of lock objects so thatthe ACE_Message_Block will - // have an interface it can use. - class Lock : public ACE_Lock_Adapter < ACE_Mutex > - { -public: - typedef ACE_Lock_Adapter < ACE_Mutex > inherited; - - Lock (void); - ~Lock (void); - - // When the Data_Block is destroyed, the Message_Block is - // holding a lock with this object. If we were to destroy - // the Lock with the Data_Block, we would have a - // segfault. Instead, the Data_Block invokes destroy() to - // mark the object as un-needed so that when the - // Message_Block invokes release() to drop the lock, the - // Lock can delete itself. - int destroy (void); - int release (void); -protected: - int destroy_; - MLD; - }; -}; - -/* - This simple derivative of ACE_Message_Block will construct our Data_Block - object to contain a unit of work. - */ -class Message_Block : public ACE_Message_Block -{ -public: - typedef ACE_Message_Block inherited; - - Message_Block (void); - Message_Block (Unit_Of_Work * _data); - - ~Message_Block (void); - -protected: - MLD; -}; - -#endif diff --git a/docs/tutorials/013/message_queue.cpp b/docs/tutorials/013/message_queue.cpp deleted file mode 100644 index 5128cbbfac4..00000000000 --- a/docs/tutorials/013/message_queue.cpp +++ /dev/null @@ -1,88 +0,0 @@ - -// $Id$ - -#include "mld.h" -#include "task.h" -#include "work.h" -#include "block.h" - -int run_test (int iterations, int threads, int subtasks) -{ - // Create a task with some subtasks. Each Task is a thread - // pool of 'threads' size. If a task has a subtask, it will - // forward the unit of work to the subtask when finished. See - // task.{h|cpp} for more details. - Task *task = new Task (subtasks); - - if (task->open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - // Give the threads a chance to get ready. -ACE_OS::sleep (ACE_Time_Value (1)); - - for (int i = 0; i < iterations; ++i) - { - // Create a custom message block that can contain our Work object - Message_Block *message = new Message_Block (new Work (i)); - - // Put the "unit of work" into the message queue - if (task->putq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - } - - // The default constructor of our custom message block will - // insert a message telling our task to shutdown. - Message_Block *message = new Message_Block (); - - // Put the shutdown request into the thread pool - if (task->putq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // Wait for the task to shut down. Any subtasks will also be - // waited for. - task->wait (); - - // Delete our Task to prevent a memory leak - delete task; - - // Ask our memory leak detector if things are OK - if (MLD_COUNTER != 0) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Memory Leak!\n")); - } - - return (0); -} - -int main (int argc, char *argv[]) -{ - // Number of Work objects to put into the Task pool - int iterations = argc > 1 ? atoi (argv[1]) : 4; - // Number of threads for each Task - int threads = argc > 2 ? atoi (argv[2]) : 2; - // Number of tasks to chain after the primary task - int subtasks = argc > 3 ? atoi (argv[3]) : 1; - - (void) run_test (iterations, threads, subtasks); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Guard < ACE_Mutex >; -template class ACE_Lock_Adapter < ACE_Mutex >; -template class ACE_Atomic_Op < ACE_Mutex, int >; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Guard<ACE_Mutex>; -#pragma instantiate ACE_Lock_Adapter<ACE_Mutex>; -#pragma instantiate ACE_Atomic_Op<ACE_Mutex, int>; -#endif /* - ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION - */ diff --git a/docs/tutorials/013/mld.cpp b/docs/tutorials/013/mld.cpp deleted file mode 100644 index 64ffdf1b144..00000000000 --- a/docs/tutorials/013/mld.cpp +++ /dev/null @@ -1,23 +0,0 @@ - -// $Id$ - -#include "mld.h" - -ACE_Atomic_Op < ACE_Mutex, int >mld::counter_ (0); - -// Increment the counter when a new mld is created... -mld::mld (void) -{ - ++counter_; -} - -// and decrement it when the object is destructed. -mld::~mld (void) -{ - --counter_; -} - -int mld::value (void) -{ - return counter_.value (); -} diff --git a/docs/tutorials/013/mld.h b/docs/tutorials/013/mld.h deleted file mode 100644 index 7dbd982e863..00000000000 --- a/docs/tutorials/013/mld.h +++ /dev/null @@ -1,49 +0,0 @@ - -// $Id$ - -#ifndef MLD_H -#define MLD_H - -#include "ace/Synch.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "ace/Singleton.h" - -/* - This is a cheap memory leak detector. Each class I want to watch over - contains an mld object. The mld object's ctor increments a global counter - while the dtor decrements it. If the counter is non-zero when the program - is ready to exit then there may be a leak. - */ - -class mld -{ -public: - mld (void); - ~mld (void); - - static int value (void); - -protected: - static ACE_Atomic_Op < ACE_Mutex, int >counter_; -}; - -// ================================================ - -/* - Just drop 'MLD' anywhere in your class definition to get cheap memory leak - detection for your class. - */ -#define MLD mld mld_ - -/* - Use 'MLD_COUNTER' in main() to see if things are OK. - */ -#define MLD_COUNTER mld::value() - -// ================================================ - -#endif diff --git a/docs/tutorials/013/page01.html b/docs/tutorials/013/page01.html deleted file mode 100644 index 217a2f9bf1d..00000000000 --- a/docs/tutorials/013/page01.html +++ /dev/null @@ -1,41 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -My intent with this tutorial was to derive from ACE_Data_Block instead -of ACE_Message_Block so that we could leverage the reference counting -nature of that object. -<P> -Along the way, I sort of got distracted... What I ended up with is a -poor excuse for ACE_Stream that implements a simple state machine. -<P> -The application is built around a thread pool where the pool's svc() -method takes work units from the message queue for processing. As -each unit is taken from the queue, the process() method is invoked to -do some work. The twist is that after processing the message, we -enqueue it into another thread pool to do more work. This continues -through a chain of thread pools until the last where the unit's fini() -method is called for finishing up any outstanding work. -<P> -The chain of thread pools is uni-directional using a singly-linked -list of Task derivatives. Each pool has the same number of tasks in -order to keep things simple. -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/013/page02.html b/docs/tutorials/013/page02.html deleted file mode 100644 index 785b0c86b75..00000000000 --- a/docs/tutorials/013/page02.html +++ /dev/null @@ -1,112 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -We'll go back to our tradition of looking at main() first. The only -change here from our "normal" thread pool is the ability to specify -the number of subtasks for the pool. (Each subtask is another thread -pool in the chain. I suppose I should have named that better...) -I've still got the custom Message_Block so that, at this level, we -don't even know about custom Data_Blocks. -<P> -<HR WIDTH="100%"> -<PRE> -#include "mld.h" -#include "task.h" -#include "work.h" -#include "block.h" - -int run_test (int iterations, int threads, int subtasks) -{ - // Create a task with some subtasks. Each Task is a thread - // pool of 'threads' size. If a task has a subtask, it will - // forward the unit of work to the subtask when finished. See - // task.{h|cpp} for more details. - Task * task = new Task(subtasks); - - if (task->open (threads) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - } - - // Give the threads a chance to get ready. - ACE_OS::sleep (ACE_Time_Value (1)); - - for (int i = 0; i < iterations; ++i) - { - // Create a custom message block that can contain our Work object - Message_Block *message = new Message_Block( new Work(i) ); - - // Put the "unit of work" into the message queue - if (task->putq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - } - - // The default constructor of our custom message block will - // insert a message telling our task to shutdown. - Message_Block *message = new Message_Block( ); - - // Put the shutdown request into the thread pool - if (task->putq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // Wait for the task to shut down. Any subtasks will also be - // waited for. - task->wait (); - - // Delete our Task to prevent a memory leak - delete task; - - // Ask our memory leak detector if things are OK - if( MLD_COUNTER->value() != 0 ) - { - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Memory Leak!\n")); - } - - return (0); -} - -int main (int argc, char *argv[]) -{ - // Number of Work objects to put into the Task pool - int iterations = argc > 1 ? atoi (argv[1]) : 4; - // Number of threads for each Task - int threads = argc > 2 ? atoi (argv[2]) : 2; - // Number of tasks to chain after the primary task - int subtasks = argc > 3 ? atoi(argv[3]) : 1; - - (void) run_test (iterations, threads, subtasks); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Application exiting\n")); - - exit (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -Nothing really surprising here... Just remember that your total -number of threads is ( ( 1 + subtasks ) * threads ). You probably -don't want to get too carried away with that! -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/013/page03.html b/docs/tutorials/013/page03.html deleted file mode 100644 index 6a3fdd798e8..00000000000 --- a/docs/tutorials/013/page03.html +++ /dev/null @@ -1,108 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -I did eventually create that ACE_Data_Block derivative that I wanted. -My purpose in doing so was to use the reference-counting -that is provided by ACE_Data_Block and ACE_Message_Block interactions. - When you're working with an object in a single -thread, it's generally not so difficult to manage it's lifetime. -That is, it doesn't tend to go out of scope or get destroyed unless -you do it on purpose. -<P> -On the other hand, if you're passing data between several threads, it -is easy to loose track of who "owns" the data at any one time. All -too frequently, data will be deleted by one thread while another is -still using it. Reference counting can prevent that. The rule of -thumb is that you increment the reference count of the object when you -hand it off to a new thread. You then decrement the count when you're -done with the object and let the object delete itself when there are -no more references. -<P> -To prove that all of that works correctly in the tutorial, I've -created a cheap Memory Leak Detector object. All mld instances -reference a thread-safe counter that is incremented when the mld is -constructed and decremented when destructed. I then insert an mld -into each of my dynamically created objects. If I get to the end of -main() and the counter isn't zero then I either didn't delete enough -or I deleted too many times. -<P> -Simple, cheap, effective. -<P> -<HR WIDTH="100%"> -<PRE> -#include "ace/Synch.h" -#include "ace/Singleton.h" - -/* - This is a cheap memory leak detector. Each class I want to watch - over contains an mld object. The mld object's ctor increments a - global counter while the dtor decrements it. If the counter is - non-zero when the program is ready to exit then there may be a leak. -*/ - -class mld -{ -public: - mld(void); - ~mld(void); - - static int value(void); - -protected: - static ACE_Atomic_Op<ACE_Mutex,int> counter_; -}; - - -/* - Just drop 'MLD' anywhere in your class definition to get cheap - memory leak detection for your class. - */ -#define MLD mld mld_ - -/* - Use 'MLD_COUNTER' in main() to see if things are OK. -*/ -#define MLD_COUNTER mld::value() - -<HR WIDTH="50%"> -<i>In the cpp file we have this:</i> - -ACE_Atomic_Op<ACE_Mutex,int> mld::counter_(0); - -// Increment the counter when a new mld is created... -mld::mld(void) -{ - ++counter_; -} - -// and decrement it when the object is destructed. -mld::~mld(void) -{ - --counter_; -} - -int mld::value(void) -{ - return counter_.value(); -} - -</PRE> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/013/page04.html b/docs/tutorials/013/page04.html deleted file mode 100644 index 4d7b714a025..00000000000 --- a/docs/tutorials/013/page04.html +++ /dev/null @@ -1,131 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -Let's look now at the changes to our ACE_Message_Block derivative and -the new ACE_Data_Block derivative. -<P> -The important thing to remember is that the data block (not the -message block) is reference counted. When you instantiate a new -ACE_Message_Block, it will create one or more ACE_Data_Block objects -to contain the data you need. Optionally, you can provide it with a -pointer to a data block. -<P> -When you finish with a message block, you should use the release() -method to make it go away. Do not ever <em>delete</em> an instance of -a message block! When you invoke release(), the message block will -invoke release() on the data block(s) it contains. If the block's -reference count goes to zero as a result then the block will <em>delete</em> -itself. -<P> -To increment the reference count of a data block, use the -duplicate() method of the message block (or blocks) to get a new -message block referencing the same data block. This is very efficient -since the actual data is not copied. -<P> -<HR WIDTH="100%"> -<PRE> -/* - In this Tutorial, we derive from ACE_Data_Block for our special - data. With the possiblilty that our Task object may forward the - unit of work on to another thread pool, we have to make sure that - the data object doesn't go out of scope unexpectedly. An - ACE_Message_Block will be deleted as soon as it's release() method - is called but the ACE_Data_Blocks it uses are reference counted and - only delete when the last reference release()es the block. We use - that trait to simply our object memory management. - */ -class Data_Block : public ACE_Data_Block -{ -public: - typedef ACE_Data_Block inherited; - - // Create a data block with a unit of work to be done - Data_Block( Unit_Of_Work * _data ); - - ~Data_Block(void); - - // Returns the work pointer - Unit_Of_Work * data(void); - -protected: - Unit_Of_Work * data_; - MLD; // Our memory leak detector - - // The ACE_Data_Block allows us to choose a locking strategy - // for making the reference counting thread-safe. The - // ACE_Lock_Adaptor<> template adapts the interface of a - // number of lock objects so that the ACE_Message_Block will - // have an interface it can use. - class Lock : public ACE_Lock_Adapter<ACE_Mutex> - { - public: - typedef ACE_Lock_Adapter<ACE_Mutex> inherited; - - Lock(void); - ~Lock(void); - - // When the Data_Block is destroyed, the Message_Block is - // holding a lock with this object. If we were to destroy - // the Lock with the Data_Block, we would have a - // segfault. Instead, the Data_Block invokes destroy() to - // mark the object as un-needed so that when the - // Message_Block invokes release() to drop the lock, the - // Lock can delete itself. - int destroy(void); - int release(void); - protected: - int destroy_; - MLD; - }; -}; - -/* - This simple derivative of ACE_Message_Block will construct our - Data_Block object to contain a unit of work. - */ -class Message_Block : public ACE_Message_Block -{ -public: - typedef ACE_Message_Block inherited; - - Message_Block( void ); - Message_Block( Unit_Of_Work * _data ); - - ~Message_Block( void ); - -protected: - MLD; -}; -</PRE> -<HR WIDTH="100%"> -<P> -One of the most difficult parts of this to get right was the Lock -object. I didn't even have it in the beginning but I soon realized -that the reference counts were getting weird. A little careful -reading of the comments and the source informed me that some sort of -locking is necessary to keep the counter sane. The simplest thing at -that point was to use the ACE_Lock_Adaptor<> to adapt ACE_Mutex -appropriately. The next trick was to ensure that the lock object was -destroyed at the proper time to prevent both memory leaks and core -dumps. The finaly product may be a little bit intimidating at first -but it's really quite simple once you understand the motivation. -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/013/page05.html b/docs/tutorials/013/page05.html deleted file mode 100644 index c258bfcd56a..00000000000 --- a/docs/tutorials/013/page05.html +++ /dev/null @@ -1,149 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -On this page we have the code for the Data_Block and Message_Block -objects. As you probably suspect from the header on the previous -page, the complicated part is in the construction and destruction of -the Data_Block. -<P> -<HR WIDTH="100%"> -<PRE> -#include "block.h" - -/* - Construct a Dat_Block to contain a unit of work. Note the careful - construction of the baseclass to set the block type and the locking - strategy. - <i>Also notice that we don't use the data area of the baseclass at - all. If we wanted to, we could have taken a second ctor parameter to - allow us the use of that space.</i> - */ -Data_Block::Data_Block( Unit_Of_Work * _data ) - : inherited(0,ACE_Message_Block::MB_DATA,0,0,new Lock(),0,0) - ,data_(_data) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Data_Block ctor for 0x%x\n", (void *) this, (void*)data_)); -} - -/* - The Lock object created in the constructor is stored in the - baseclass and available through the locking_strategy() method. We - can cast it's value to our Lock object and invoke the destroy() to - indicate that we want it to go away when the lock is released. - <i>In other tutorials I've gone to quite a bit of trouble to avoid - the kind of cast you see here. If I had stuck to that form it might - look something like this: - ACE_Lock * ls = this->locking_stragety(); - Lock * my_lock = (Lock*)ls; - my_lock->destroy();</i> - */ -Data_Block::~Data_Block(void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Data_Block dtor for 0x%x\n", (void *) this, (void*)data_)); - ((Lock*)locking_strategy())->destroy(); - delete data_; -} - -/* - Return the data -*/ -Unit_Of_Work * Data_Block::data(void) -{ - return this->data_; -} - -Data_Block::Lock::Lock(void) - : destroy_(0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Lock ctor\n", (void *) this )); -} - -Data_Block::Lock::~Lock(void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Lock dtor\n", (void *) this )); -} - -/* - Set our destroy_ flag so that the next lock release will cause us to - be deleted. -*/ -int Data_Block::Lock::destroy(void) -{ - ++destroy_; - return(0); -} - -/* - Mutexes have acquire() and release() methods. We've overridden the - latter so that when the object we're protecting goes away, we can - make ourselves go away after the lock is released. -*/ -int Data_Block::Lock::release(void) -{ - int rval = inherited::release(); - if( destroy_ ) - { - delete this; - } - return rval; -} - -/* - Create an baseclass unit of work when we instantiate a hangup message. -*/ -Message_Block::Message_Block( void ) - : inherited( new Data_Block( new Unit_Of_Work() ) ) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block ctor for shutdown\n", (void *) this )); - this->msg_type( MB_HANGUP ); -} - -/* - Store the unit of work in a Data_Block and initialize the baseclass - with that data. -*/ -Message_Block::Message_Block( Unit_Of_Work * _data ) - : inherited( new Data_Block(_data) ) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block ctor for 0x%x\n", (void *) this, (void*)_data)); -} - -Message_Block::~Message_Block( void ) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Message_Block dtor\n", (void *) this )); -} -</PRE> -<HR WIDTH="100%"> -<P> -I hope that wasn't too confusing. The locking strategy can be a bit -daunting at times. The worst problem is dealing with the fact -that the lock is held while the object being guarded by the lock is -being destroyed. But the only object that has a reference to the -(dynamically created) lock object is the very thing being deleted. We -would be in a world of hurt if the lock's release() method had not -been created virtual! By simply overridding that method we can get -ourselves out of a nasty situation. -<P> -The rest of the code is pretty cut and dried. We could have had the -hangup indicator create a data block with a null unit of work but it's -more orthgonal for the thread pool if we always have a valid pointer. -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page06.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/013/page06.html b/docs/tutorials/013/page06.html deleted file mode 100644 index 972d5755e19..00000000000 --- a/docs/tutorials/013/page06.html +++ /dev/null @@ -1,286 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -Let's take a look now at the new Task object. This will obviously be -different from the Tasks we've created before but I think you'll be -surprised at how relatively simple it actually is. -<P> -Remember that the goal of this tutorial was to use the reference -counting abilities of the ACE_Data_Block. The only way to show that -effectively is to have a data block passed between different threads. -A thread pool isn't really going to do that so, instead, our new Task -can be part of a chain of tasks. In that way, each Task can pass the -data on to another and satisfy our need for moving the ACE_Data_Block -around. -If we've done the reference counting correctly then none of our tasks -will be trying to work with deleted data and we won't have any memory -leaks at the end. -<P> -There's not much to the header, so I've included it and the cpp file -on this one page. -<P> -<HR WIDTH="100%"> -<PRE> - -#include "ace/Task.h" -#include "mld.h" - -/* - This is much like the Task we've used in the past for implementing a - thread pool. This time, however, I've made the Task an element in a - singly-linked list. As the svc() method finishes the process() on a - unit of work, it will enqueue that unit of work to the next_ Task if - there is one. If the Task does not have a next_ Task, it will - invoke the unit of work object's fini() method after invoking process(). - */ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - // Construct ourselves and an optional number of subtasks - // chained beyond us. - Task ( int sub_tasks = 0 ); - ~Task (void); - - // Open the Task with the proper thread-pool size - int open (int threads = 1 ); - - // Take Unit_Of_Work objects from the thread pool and invoke - // their process() and/or fini() as appropriate. - int svc (void); - - // Shut down the thread pool and it's associated subtasks - int close (u_long flags = 0); - - // Wait for the pool and subtasks to close - int wait(void); - -protected: - ACE_Barrier * barrier_; - Task * next_; - MLD; -}; - -<HR WIDTH="50%"> - -#include "task.h" -#include "block.h" -#include "work.h" - -/* - Construct the Task with zero or more subtasks. If subtasks are requested, - we assign our next_ pointer to the first of those and let it worry about - any remaining subtasks. - */ -Task::Task (int sub_tasks) -: barrier_ (0) - ,next_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); - if (sub_tasks) - { - next_ = new Task (--sub_tasks); - } -} - -/* - Delete our barrier object and any subtasks we may have. - */ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - delete barrier_; - delete next_; -} - -/* - Open our thread pool with the requested number of threads. If subtasks are - enabled, they inherit the thread-pool size. Make sure that the subtasks can - be opened before we open our own threadpool. - */ -int Task::open (int threads) -{ - if (next_) - { - if (next_->open (threads) == -1) - { - return -1; - } - } - - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - Close ourselves and any subtasks. This just prints a message so that we can - assure ourselves things are cleaned up correctly. - */ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - if (next_) - { - next_->close (flags); - } - - return (0); -} - -/* - Wait for all of the threads in our pool to exit and then wait for any - subtasks. When called from the front of the task chain, this won't return - until all thread pools in the chain have exited. - */ -int Task::wait (void) -{ - inherited::wait (); - if (next_) - { - next_->wait (); - } - return (0); -} - -/* - Like the thread-pools before, this is where all of the work is done. - */ -int Task::svc (void) -{ - // Wait for all threads to get this far before continuing. - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %u\n", (void *) this, ACE_Thread::self ())); - - // getq() wants an ACE_Message_Block so we'll start out with one - // of those. We could do some casting (or even auto-casting) to - // avoid the extra variable but I prefer to be clear about our actions. - ACE_Message_Block *message; - - // What we really put into the queue was our Message_Block. - // After we get the message from the queue, we'll cast it to this - // so that we know how to work on it. - Message_Block *message_block; - - // And, of course, our Message_Block contains our Data_Block - // instead of the typical ACE_Data_Block - Data_Block *data_block; - - // Even though we put Work objects into the queue, we take them - // out using the baseclass pointer. This allows us to create new - // derivatives without having to change this svc() method. - Unit_Of_Work *work; - - while (1) - { - // Get the ACE_Message_Block - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - // "Convert" it to our Message_Block - message_block = (Message_Block *) message; - - // Get the ACE_Data_Block and "convert" to Data_Block in one step. - data_block = (Data_Block *) (message_block->data_block ()); - - // Get the unit of work from the data block - work = data_block->data (); - - // Show the object's instance value and "type name" - work->who_am_i (); - work->what_am_i (); - - // If there is a hangup we need to tell our pool-peers as - // well as any subtasks. - if (message_block->msg_type () == ACE_Message_Block::MB_HANGUP) - { - // duplicate()ing the message block will increment the - // reference counts on the data blocks. This allows us - // to safely release() the message block. The rule of - // thumb is that if you pass a message block to a new - // owner, duplicate() it. Then you can release() when - // you're done and not worry about memory leaks. - if (this->putq (message_block->duplicate ()) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // If we have a subtask, duplicate() the message block - // again and pass it to that task's queue - if (next_ && next_->putq (message_block->duplicate ()) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // We're now done with our copy of the block, so we can - // release it. Our peers/subtasks have their own message - // block to access the shared data blocks. - message_block->release (); - - break; - } - - // If this isn't a hangup/shutdown message then we tell the - // unit of work to process() for a while. - work->process (); - - if (next_) - { - // If we have subtasks, we pass the block on to them. Notice - // that I don't bother to duplicate() the block since I won't - // release it in this case. I could have invoked - // duplicate() in the puq() and then release() - // afterwards. Either is acceptable. - if (next_->putq (message_block) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - else - { - // If we don't have subtasks then invoke fini() to tell - // the unit of work that we won't be invoking process() - // any more. Then release() the block. This release() - // would not change if we duplicate()ed in the above conditional - work->fini (); - message_block->release (); - } - - // Pretend that the work takes some time... - ACE_OS::sleep (ACE_Time_Value (0, 250)); - } - - return (0); -} -</PRE> -<HR WIDTH="100%"> -<P> -So you see... it wasn't really that much more complicated. We really -just have to remember to pass to <i>next_</i> when we finish working -on the data. If your Unit_Of_Work derivative is going to implement a -state machine be sure that you also implement a fini() method -<em>or</em> ensure that your chain of subtasks is large enough for all -possible states. -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page07.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/013/page07.html b/docs/tutorials/013/page07.html deleted file mode 100644 index f29609074e4..00000000000 --- a/docs/tutorials/013/page07.html +++ /dev/null @@ -1,244 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -I've been trying to justify the chain of tasks by talking about a -Work object that implements a state machine. The idea is that your -Work object has to perform a series of discrete steps to complete it's -function. Traditionally, all of those steps would take place in one -thread of execution. That thread would probably be one from a Task -thread pool. -<P> -Suppose, however, that some of those steps spend a lot of time waiting -for disk IO. You could find that all of your thread-pool threads -are just sitting there waiting for the disk. You might then be -tempted to increase the thread pool size to get more work through. -However, if some of the stages are memory intensive, you could run out -of memory if all of the workers get to that state at the same time. -<P> -One solution might be to have different thread pools for each state. -Each pool could have it's size tuned appropriately for the work that -would be done there. That's where the chain of Tasks comes in. - In this tutorial's implementation I've taken the -easy route and set all of the thread pools to the same size but a more -realistic solution would be to set each thread pool in the chain to a -specific size as needed by that state of operation. -<P> -There's not much to this header either so I've combined it with the -cpp file as with task. -<P> -<HR WIDTH="100%"> -<PRE> -#include "ace/Log_Msg.h" -#include "ace/Synch.h" -#include "mld.h" - -/* - Our specilized message queue and thread pool will know how to do "work" on - our Unit_Of_Work baseclass. - */ -class Unit_Of_Work -{ -public: - Unit_Of_Work (void); - - virtual ~ Unit_Of_Work (void); - - // Display the object instance value - void who_am_i (void); - - // The baseclass can override this to show it's "type name" - virtual void what_am_i (void); - - // This is where you do application level logic. It will be - // called once for each thread pool it passes through. It - // would typically implement a state machine and execute a - // different state on each call. - virtual int process (void); - - // This is called by the last Task in the series (see task.h) - // in case our process() didn't get through all of it's states. - virtual int fini (void); - -protected: - ACE_Atomic_Op < ACE_Mutex, int >state_; - MLD; -}; - -/* - A fairly trivial work derivative that implements an equally trivial state - machine in process() - */ -class Work : public Unit_Of_Work -{ -public: - Work (void); - - Work (int message); - - virtual ~ Work (void); - - void what_am_i (void); - - int process (void); - - int fini (void); - -protected: - int message_; - MLD; -}; - -<HR WIDTH="50%"> - -#include "work.h" - -/* - Initialize the state to zero - */ -Unit_Of_Work::Unit_Of_Work (void) -: state_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work ctor\n", (void *) this)); -} - -Unit_Of_Work::~Unit_Of_Work (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work dtor\n", (void *) this)); -} - -/* - Display our instance value - */ -void Unit_Of_Work::who_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work instance\n", (void *) this)); -} - -/* - Dispay our type name - */ -void Unit_Of_Work::what_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x I am a Unit_Of_Work object\n", (void *) this)); -} - -/* - Return failure. You should always derive from Unit_Of_Work... - */ -int Unit_Of_Work::process (void) -{ - return -1; -} - -/* - ditto - */ -int Unit_Of_Work::fini (void) -{ - return -1; -} - -/* - Default constructor has no "message number" - */ -Work::Work (void) -:message_ (-1) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work ctor\n", (void *) this)); -} - -/* - The useful constructor remembers which message it is and will tell you if - you ask. - */ -Work::Work (int message) -: message_ (message) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work ctor for message %d\n", (void *) this, message_)); -} - -Work::~Work (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work dtor\n", (void *) this)); -} - -/* - This objects type name is different from the baseclass - */ -void Work::what_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x I am a Work object for message %d\n", (void *) this, message_)); -} - -/* - A very simple state machine that just walks through three stages. If it is - called more than that, it will tell you not to bother. - */ -int Work::process (void) -{ - switch (++state_) - { - case 1: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage One\n", (void *) this)); - break; - case 2: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage Two\n", (void *) this)); - break; - case 3: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage Three\n", (void *) this)); - break; - default: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x No work to do in state %d\n", - (void *) this, state_.value ())); - break; - } - return (0); -} - -/* - If you don't have enough subtasks in the chain then the state machine won't - progress to the end. The fini() hook will allow us to recover from that by - executing the remaining states in the final task of the chain. - */ -int Work::fini (void) -{ - while (state_.value () < 3) - { - if (this->process () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "process"), -1); - } - } - return (0); -} - -</PRE> - -<HR WIDTH="100%"> -<P> -And that is that. For a more complex machine that may want to "jump -states" you would have to set some "state information" (sorry, bad -choice of terminology again) so that process() could decide what to do -at each call. You might also modify Task::svc() so that it will -respect the return value of process() and do something useful with the -information. -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page08.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/013/page08.html b/docs/tutorials/013/page08.html deleted file mode 100644 index ce8e9158922..00000000000 --- a/docs/tutorials/013/page08.html +++ /dev/null @@ -1,44 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 013</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 013</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Multiple thread pools</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> -<P> -And that's the end of another tutorial. This one is probably the most -complicated so far because I've introduced or expanded upon -a number of different -concepts. Namely: state machines, reference counting and task -chaining. I hope I didn't complicate things to the point where the -lesson got lost in the noise. As always, feel free to drop a note to -the ACE-Users mailing list if you feel that some of this could use a -little more explaination. - -<P> -<UL> -<LI><A HREF="Makefile">Makefile</A> -<LI><A HREF="block.cpp">block.cpp</A> -<LI><A HREF="block.h">block.h</A> -<LI><A HREF="message_queue.cpp">message_queue.cpp</A> -<LI><A HREF="mld.cpp">mld.cpp</A> -<LI><A HREF="mld.h">mld.h</A> -<LI><A HREF="task.cpp">task.cpp</A> -<LI><A HREF="task.h">task.h</A> -<LI><A HREF="work.cpp">work.cpp</A> -<LI><A HREF="work.h">work.h</A> -</UL> -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>]</CENTER> - -</BODY> -</HTML> diff --git a/docs/tutorials/013/task.cpp b/docs/tutorials/013/task.cpp deleted file mode 100644 index 6ea62ef7de7..00000000000 --- a/docs/tutorials/013/task.cpp +++ /dev/null @@ -1,193 +0,0 @@ - -// $Id$ - -#include "task.h" -#include "block.h" -#include "work.h" - -/* - Construct the Task with zero or more subtasks. If subtasks are requested, - we assign our next_ pointer to the first of those and let it worry about - any remaining subtasks. - */ -Task::Task (int sub_tasks) -: barrier_ (0) - ,next_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task ctor 0x%x\n", (void *) this)); - if (sub_tasks) - { - next_ = new Task (--sub_tasks); - } -} - -/* - Delete our barrier object and any subtasks we may have. - */ -Task::~Task (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task dtor 0x%x\n", (void *) this)); - - delete barrier_; - delete next_; -} - -/* - Open our thread pool with the requested number of threads. If subtasks are - enabled, they inherit the thread-pool size. Make sure that the subtasks can - be opened before we open our own threadpool. - */ -int Task::open (int threads) -{ - if (next_) - { - if (next_->open (threads) == -1) - { - return -1; - } - } - - barrier_ = new ACE_Barrier (threads); - return this->activate (THR_NEW_LWP, threads); -} - -/* - Close ourselves and any subtasks. This just prints a message so that we can - assure ourselves things are cleaned up correctly. - */ -int Task::close (u_long flags) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task close 0x%x\n", (void *) this)); - if (next_) - { - next_->close (flags); - } - - return (0); -} - -/* - Wait for all of the threads in our pool to exit and then wait for any - subtasks. When called from the front of the task chain, this won't return - until all thread pools in the chain have exited. - */ -int Task::wait (void) -{ - inherited::wait (); - if (next_) - { - next_->wait (); - } - return (0); -} - -/* - Like the thread-pools before, this is where all of the work is done. - */ -int Task::svc (void) -{ - // Wait for all threads to get this far before continuing. - this->barrier_->wait (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Task 0x%x starts in thread %u\n", (void *) this, ACE_Thread::self ())); - - // getq() wants an ACE_Message_Block so we'll start out with one - // of those. We could do some casting (or even auto-casting) to - // avoid the extra variable but I prefer to be clear about our actions. - ACE_Message_Block *message; - - // What we really put into the queue was our Message_Block. - // After we get the message from the queue, we'll cast it to this - // so that we know how to work on it. - Message_Block *message_block; - - // And, of course, our Message_Block contains our Data_Block - // instead of the typical ACE_Data_Block - Data_Block *data_block; - - // Even though we put Work objects into the queue, we take them - // out using the baseclass pointer. This allows us to create new - // derivatives without having to change this svc() method. - Unit_Of_Work *work; - - while (1) - { - // Get the ACE_Message_Block - if (this->getq (message) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getq"), -1); - } - - // "Convert" it to our Message_Block - message_block = (Message_Block *) message; - - // Get the ACE_Data_Block and "convert" to Data_Block in one step. - data_block = (Data_Block *) (message_block->data_block ()); - - // Get the unit of work from the data block - work = data_block->data (); - - // Show the object's instance value and "type name" - work->who_am_i (); - work->what_am_i (); - - // If there is a hangup we need to tell our pool-peers as - // well as any subtasks. - if (message_block->msg_type () == ACE_Message_Block::MB_HANGUP) - { - // duplicate()ing the message block will increment the - // reference counts on the data blocks. This allows us - // to safely release() the message block. The rule of - // thumb is that if you pass a message block to a new - // owner, duplicate() it. Then you can release() when - // you're done and not worry about memory leaks. - if (this->putq (message_block->duplicate ()) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // If we have a subtask, duplicate() the message block - // again and pass it to that task's queue - if (next_ && next_->putq (message_block->duplicate ()) == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - - // We're now done with our copy of the block, so we can - // release it. Our peers/subtasks have their own message - // block to access the shared data blocks. - message_block->release (); - - break; - } - - // If this isn't a hangup/shutdown message then we tell the - // unit of work to process() for a while. - work->process (); - - if (next_) - { - // If we have subtasks, we pass the block on to them. Notice - // that I don't bother to duplicate() the block since I won't - // release it in this case. I could have invoked - // duplicate() in the puq() and then release() - // afterwards. Either is acceptable. - if (next_->putq (message_block) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "putq"), -1); - } - else - { - // If we don't have subtasks then invoke fini() to tell - // the unit of work that we won't be invoking process() - // any more. Then release() the block. This release() - // would not change if we duplicate()ed in the above conditional - work->fini (); - message_block->release (); - } - - // Pretend that the work takes some time... - ACE_OS::sleep (ACE_Time_Value (0, 250)); - } - - return (0); -} diff --git a/docs/tutorials/013/task.h b/docs/tutorials/013/task.h deleted file mode 100644 index 8c11a8872c6..00000000000 --- a/docs/tutorials/013/task.h +++ /dev/null @@ -1,53 +0,0 @@ - -// $Id$ - -#ifndef TASK_H -#define TASK_H - -#include "ace/Task.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "mld.h" - -/* - This is much like the Task we've used in the past for implementing a thread - pool. This time, however, I've made the Task an element in a singly-linked - list. As the svc() method finishes the process() on a unit of work, it - will enqueue that unit of work to the next_ Task if there is one. If the - Task does not have a next_ Task, it will invoke the unit of work object's - fini() method after invoking process(). - */ -class Task : public ACE_Task < ACE_MT_SYNCH > -{ -public: - - typedef ACE_Task < ACE_MT_SYNCH > inherited; - - // Construct ourselves and an optional number of subtasks - // chained beyond us. - Task (int sub_tasks = 0); - ~Task (void); - - // Open the Task with the proper thread-pool size - int open (int threads = 1); - - // Take Unit_Of_Work objects from the thread pool and invoke - // their process() and/or fini() as appropriate. - int svc (void); - - // Shut down the thread pool and it's associated subtasks - int close (u_long flags = 0); - - // Wait for the pool and subtasks to close - int wait (void); - -protected: - ACE_Barrier * barrier_; - Task *next_; - MLD; -}; - -#endif diff --git a/docs/tutorials/013/work.cpp b/docs/tutorials/013/work.cpp deleted file mode 100644 index 332353052a3..00000000000 --- a/docs/tutorials/013/work.cpp +++ /dev/null @@ -1,124 +0,0 @@ - -// $Id$ - -#include "work.h" - -/* - Initialize the state to zero - */ -Unit_Of_Work::Unit_Of_Work (void) -: state_ (0) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work ctor\n", (void *) this)); -} - -Unit_Of_Work::~Unit_Of_Work (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work dtor\n", (void *) this)); -} - -/* - Display our instance value - */ -void Unit_Of_Work::who_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Unit_Of_Work instance\n", (void *) this)); -} - -/* - Dispay our type name - */ -void Unit_Of_Work::what_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x I am a Unit_Of_Work object\n", (void *) this)); -} - -/* - Return failure. You should always derive from Unit_Of_Work... - */ -int Unit_Of_Work::process (void) -{ - return -1; -} - -/* - ditto - */ -int Unit_Of_Work::fini (void) -{ - return -1; -} - -/* - Default constructor has no "message number" - */ -Work::Work (void) -:message_ (-1) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work ctor\n", (void *) this)); -} - -/* - The useful constructor remembers which message it is and will tell you if - you ask. - */ -Work::Work (int message) -: message_ (message) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work ctor for message %d\n", (void *) this, message_)); -} - -Work::~Work (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Work dtor\n", (void *) this)); -} - -/* - This objects type name is different from the baseclass - */ -void Work::what_am_i (void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x I am a Work object for message %d\n", (void *) this, message_)); -} - -/* - A very simple state machine that just walks through three stages. If it is - called more than that, it will tell you not to bother. - */ -int Work::process (void) -{ - switch (++state_) - { - case 1: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage One\n", (void *) this)); - break; - case 2: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage Two\n", (void *) this)); - break; - case 3: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x Stage Three\n", (void *) this)); - break; - default: - ACE_DEBUG ((LM_DEBUG, "(%P|%t) 0x%x No work to do in state %d\n", - (void *) this, state_.value ())); - break; - } - return (0); -} - -/* - If you don't have enough subtasks in the chain then the state machine won't - progress to the end. The fini() hook will allow us to recover from that by - executing the remaining states in the final task of the chain. - */ -int Work::fini (void) -{ - while (state_.value () < 3) - { - if (this->process () == -1) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "process"), -1); - } - } - return (0); -} diff --git a/docs/tutorials/013/work.h b/docs/tutorials/013/work.h deleted file mode 100644 index 0cf60afd1ed..00000000000 --- a/docs/tutorials/013/work.h +++ /dev/null @@ -1,72 +0,0 @@ - -// $Id$ - -#ifndef WORK_H -#define WORK_H - -#include "ace/Log_Msg.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "ace/Synch.h" -#include "mld.h" - -/* - Our specilized message queue and thread pool will know how to do "work" on - our Unit_Of_Work baseclass. - */ -class Unit_Of_Work -{ -public: - Unit_Of_Work (void); - - virtual ~ Unit_Of_Work (void); - - // Display the object instance value - void who_am_i (void); - - // The baseclass can override this to show it's "type name" - virtual void what_am_i (void); - - // This is where you do application level logic. It will be - // called once for each thread pool it passes through. It - // would typically implement a state machine and execute a - // different state on each call. - virtual int process (void); - - // This is called by the last Task in the series (see task.h) - // in case our process() didn't get through all of it's states. - virtual int fini (void); - -protected: - ACE_Atomic_Op < ACE_Mutex, int >state_; - MLD; -}; - -/* - A fairly trivial work derivative that implements an equally trivial state - machine in process() - */ -class Work : public Unit_Of_Work -{ -public: - Work (void); - - Work (int message); - - virtual ~ Work (void); - - void what_am_i (void); - - int process (void); - - int fini (void); - -protected: - int message_; - MLD; -}; - -#endif diff --git a/docs/tutorials/014/EndTask.h b/docs/tutorials/014/EndTask.h deleted file mode 100644 index 1666c5e8869..00000000000 --- a/docs/tutorials/014/EndTask.h +++ /dev/null @@ -1,80 +0,0 @@ - -// $Id$ - -// EndTask.h -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#ifndef ENDTASK_H -#define ENDTASK_H - -#include "Task.h" - -// When you setup a Stream and push your modules on, -// there are two additional modules that go unseen -// by the user. -// -// The Stream pushes on a Stream_Head in front of -// your first module, and a Stream_Tail behind your -// last module. -// -// If your put() a message to the Stream Tail, it -// assumes you did so in error. This simple EndTask -// class allows you to push a message to it and just -// have it safely Go Away. -// -// All this Task does is release the Message_Block -// and return 0. It's a suitable black-hole. - - -class EndTask : public Task -{ - -public: - - typedef Task inherited; - - EndTask(const char *nameOfTask) : - inherited(nameOfTask, 0) { - - // when we get open()'d, it with 0 threads - // since there is actually no processing to do. - - cerr << __LINE__ << " " << __FILE__ << endl; - }; - - virtual int open(void *) - { - cerr << __LINE__ << " " << __FILE__ << endl; - return 0; - } - - virtual int open(void) - { - cerr << __LINE__ << " " << __FILE__ << endl; - return 0; - } - - virtual ~EndTask(void) { - }; - - virtual int put(ACE_Message_Block *message, - ACE_Time_Value *timeout) { - - cerr << __LINE__ << " " << __FILE__ << endl; - ACE_UNUSED_ARG(timeout); - - // we don't have anything to do, so - // release() the message. - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s EndTask::put() -- releasing Message_Block\n", this->nameOfTask())); - message->release(); - return 0; - }; - -}; - -#endif // ENDTASK_H diff --git a/docs/tutorials/014/Makefile b/docs/tutorials/014/Makefile deleted file mode 100644 index 42e20ef079f..00000000000 --- a/docs/tutorials/014/Makefile +++ /dev/null @@ -1,74 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = stream - -FILES = Task - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) -SRC += $(addsuffix .cpp,$(FILES)) - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -rename : # - for i in *.cxx ; do \ - n=`expr "$$i" : "\(.*\).cxx"` ;\ - mv $$i $$n.cpp ;\ - done - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../007/fix.Makefile - -.depend : # - touch .depend - -HTML : # - [ -f hdr ] || $(MAKE) UNSHAR - perl ../combine *.pre - -SHAR : # - [ ! -f combine.shar ] || exit 1 - shar -T hdr bodies *.pre > combine.shar && rm -f hdr bodies *.pre - -UNSHAR : # - sh combine.shar - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include .depend diff --git a/docs/tutorials/014/Task.cpp b/docs/tutorials/014/Task.cpp deleted file mode 100644 index 51b4e540be5..00000000000 --- a/docs/tutorials/014/Task.cpp +++ /dev/null @@ -1,210 +0,0 @@ - -// $Id$ - -// Task.cxx -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#include <ace/Message_Block.h> - -#include "Task.h" - -Task::Task(const char * nameOfTask, - int numberOfThreads) - : d_numberOfThreads(numberOfThreads), - d_barrier(numberOfThreads) -{ - // Just initialize our name, number of threads, and barrier. - - ACE_OS::strcpy(d_nameOfTask, nameOfTask); -} - -Task::~Task(void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::~Task() -- once per Task\n", d_nameOfTask)); -} - -int Task::open(void *arg) -{ - ACE_UNUSED_ARG(arg); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::open() -- once per Task\n", d_nameOfTask)); - - // call ACE_Task::activate() to spawn the threads using - // our Task::svc() as the function to be run. - - // FMM -- Frequently Made Mistake -- - // - // If you specify the flag THR_DETACHED when activating the - // Task, you will get an assert() violation during close(), - // since the Task waits for all of its threads to rejoin. - // - - return this->activate(THR_NEW_LWP, d_numberOfThreads); -} - -int Task::put(ACE_Message_Block *message, - ACE_Time_Value *timeout) -{ - // ACE_Stream uses the put() method of Tasks to send messages. - // This defaultly does nothing. Here we link our put() method - // directly to our putq() method, so that Messages put() to us - // will appear in the Message_Queue that is checked by the - // service threads. - - return this->putq(message, timeout); -} - -int Task::close(u_long flags) -{ - - // When the Stream closes the Module, the Module then close()'s the Task - // and passing a value of (1) as the flag. - - // When a service thread exits, it calls close() with a value that is not - // (1). - - // We use this fact to tell the difference between closing a service thread, - // and closing the main Task itself. - - if (flags == 1) { - - // The Module has asked to close the main Task. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::close() -- flags == 1 -- once per Task\n", d_nameOfTask)); - - // We create a Message_Block... - - ACE_Message_Block *hangupBlock = new ACE_Message_Block(); - - // And make it of the type MB_HANGUP. - - hangupBlock->msg_type(ACE_Message_Block::MB_HANGUP); - - // We then send this Block into the Message_Queue to be seen by the - // service threads. - - // Once again we duplicate() the Block as send it off... - - if (this->putq(hangupBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::close() putq"), -1); - } - - // ..and we're free to release() our copy of it. - - hangupBlock->release(); - - // Now, all we have to do is wait() for the service threads to all - // exit. This is where using THR_DETACHED in the activate() method - // will come back to haunt you. - - // The Stream waits until this returns before attempting to remove - // the next Module/Task group in the Stream. This allows for an - // orderly shutting down of the Stream. - - return this->wait(); - - - } else { - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::close() -- flags != 1 -- once per servicing thread\n", d_nameOfTask)); - - // This is where we can clean up any mess left over by each service thread. - // In this Task, there is nothing to do. - - } - - return 0; - -} - -int Task::svc(void) -{ - - // This is the function that our service threads run once they are spawned. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- once per servicing thread\n", d_nameOfTask)); - - // First, we wait until all of our peer service threads have arrived - // at this point also. - - d_barrier.wait(); - - ACE_Message_Block *messageBlock; - - while (1) { - - // And now we loop almost infinitely. - - // getq() will block until a Message_Block is available to be read, - // or an error occurs. - - if ( this->getq(messageBlock, 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::svc() getq"), -1); - } - - if (messageBlock->msg_type() == ACE_Message_Block::MB_HANGUP) { - - // If the Message_Block is of type MB_HANGUP, then we're being asked - // to shut down nicely. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- HANGUP block received\n", d_nameOfTask)); - - // So, we duplicate the Block, and put it back into the Message_Queue, - // in case there are some more peer service threads still running. - - if (this->putq(messageBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::svc() putq"), -1); - } - - // We release our copy of the Block. - messageBlock->release(); - - // And we break out of the nearly infinitely loop, and - // head towards close() ourselves. - break; - } - - // If we're here, then we've received a Message_Block that was - // not informing us to quit, so we're assuming it's a valid - // meaningful Block. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- Normal block received\n", d_nameOfTask)); - - // We grab the read-pointer from the Block, and display it through a DEBUG statement. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) %s Task::svc() -- %s\n", d_nameOfTask, messageBlock->rd_ptr() )); - - // We pretend that this takes to time to process the Block. - // If you're on a fast machine, you might have to raise this - // value to actually witness different threads handling - // blocks for each Task. - - ACE_OS::sleep (ACE_Time_Value (0, 250)); - - // Since we're part of a Stream, we duplicate the Block, and - // send it on to the next Task. - - if (put_next(messageBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::svc() put_next"), -1); - } - - // And then we release our copy of it. - - messageBlock->release(); - - } - - return 0; - -} - - -const char * Task::nameOfTask(void) const -{ - return d_nameOfTask; -} diff --git a/docs/tutorials/014/Task.h b/docs/tutorials/014/Task.h deleted file mode 100644 index adb533c01ef..00000000000 --- a/docs/tutorials/014/Task.h +++ /dev/null @@ -1,68 +0,0 @@ - -// $Id$ - -// Task.h -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#ifndef TASK_H -#define TASK_H - -#include <ace/Task.h> -#include <ace/Synch.h> - -// Always typedef when possible. - -typedef ACE_Task<ACE_MT_SYNCH> Task_Base; - -class Task : public Task_Base -{ - -public: - - typedef Task_Base inherited; - // This is just good form. - - Task(const char *nameOfTask, - int numberOfThreads); - // Initialize our Task with a name, - // and number of threads to spawn. - - virtual ~Task(void); - - virtual int open(void *arg); - // This is provided to prevent compiler complaints - // about hidden virtual functions. - - virtual int close(u_long flags); - // This closes down the Task and all service threads. - - virtual int put(ACE_Message_Block *message, - ACE_Time_Value *timeout); - // This is the interface that ACE_Stream uses to - // communicate with our Task. - - virtual int svc(void); - // This is the actual service loop each of the service - // threads iterates through. - - const char *nameOfTask(void) const; - // Returns the name of this Task. - -private: - - int d_numberOfThreads; - char d_nameOfTask[64]; - - ACE_Barrier d_barrier; - // Simple Barrier to make sure all of our service - // threads have entered their loop before accepting - // any messages. -}; - - -#endif // TASK_H diff --git a/docs/tutorials/014/combine.shar b/docs/tutorials/014/combine.shar deleted file mode 100644 index c4af4862e35..00000000000 --- a/docs/tutorials/014/combine.shar +++ /dev/null @@ -1,323 +0,0 @@ -#!/bin/sh -# This is a shell archive (produced by GNU sharutils 4.2). -# To extract the files from this archive, save it to some FILE, remove -# everything before the `!/bin/sh' line above, then type `sh FILE'. -# -# Made on 1998-10-20 19:37 EDT by <jcej@chiroptera.tragus.org>. -# Source directory was `/var/home/jcej/projects/ACE_wrappers/docs/tutorials/014'. -# -# Existing files will *not* be overwritten unless `-c' is specified. -# -# This shar contains: -# length mode name -# ------ ---------- ------------------------------------------ -# 414 -rw-r--r-- hdr -# 44 -rw-r--r-- bodies -# 1023 -rw-r--r-- page01.pre -# 231 -rw-r--r-- page02.pre -# 651 -rw-r--r-- page03.pre -# 439 -rw-r--r-- page04.pre -# 1079 -rw-r--r-- page05.pre -# -save_IFS="${IFS}" -IFS="${IFS}:" -gettext_dir=FAILED -locale_dir=FAILED -first_param="$1" -for dir in $PATH -do - if test "$gettext_dir" = FAILED && test -f $dir/gettext \ - && ($dir/gettext --version >/dev/null 2>&1) - then - set `$dir/gettext --version 2>&1` - if test "$3" = GNU - then - gettext_dir=$dir - fi - fi - if test "$locale_dir" = FAILED && test -f $dir/shar \ - && ($dir/shar --print-text-domain-dir >/dev/null 2>&1) - then - locale_dir=`$dir/shar --print-text-domain-dir` - fi -done -IFS="$save_IFS" -if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED -then - echo=echo -else - TEXTDOMAINDIR=$locale_dir - export TEXTDOMAINDIR - TEXTDOMAIN=sharutils - export TEXTDOMAIN - echo="$gettext_dir/gettext -s" -fi -touch -am 1231235999 $$.touch >/dev/null 2>&1 -if test ! -f 1231235999 && test -f $$.touch; then - shar_touch=touch -else - shar_touch=: - echo - $echo 'WARNING: not restoring timestamps. Consider getting and' - $echo "installing GNU \`touch', distributed in GNU File Utilities..." - echo -fi -rm -f 1231235999 $$.touch -# -if mkdir _sh14739; then - $echo 'x -' 'creating lock directory' -else - $echo 'failed to create lock directory' - exit 1 -fi -# ============= hdr ============== -if test -f 'hdr' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'hdr' '(file already exists)' -else - $echo 'x -' extracting 'hdr' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'hdr' && -<HTML> -<HEAD> -X <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> -X <META NAME="Author" CONTENT="Bob McWhirter"> -X <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> -X -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> -X -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> -X -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 1012190598 'hdr' && - chmod 0644 'hdr' || - $echo 'restore of' 'hdr' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'hdr:' 'MD5 check failed' -25304aa689283dcbed9531b68e7ae2b9 hdr -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'hdr'`" - test 414 -eq "$shar_count" || - $echo 'hdr:' 'original size' '414,' 'current size' "$shar_count!" - fi -fi -# ============= bodies ============== -if test -f 'bodies' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'bodies' '(file already exists)' -else - $echo 'x -' extracting 'bodies' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'bodies' && -PAGE=2 -Task.h -Task.cpp -EndTask.h -stream.cpp -SHAR_EOF - $shar_touch -am 1020193698 'bodies' && - chmod 0644 'bodies' || - $echo 'restore of' 'bodies' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'bodies:' 'MD5 check failed' -43305b4b15975a1e4cbd99b6d3592c12 bodies -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`" - test 44 -eq "$shar_count" || - $echo 'bodies:' 'original size' '44,' 'current size' "$shar_count!" - fi -fi -# ============= page01.pre ============== -if test -f 'page01.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page01.pre' '(file already exists)' -else - $echo 'x -' extracting 'page01.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page01.pre' && -X -<p><b>ACE_Stream</b> is handy when you have several <b>ACE_Task</b> objects -that you would like to link together. -X -<p>An intermediate class you we will deal with is the <b>ACE_Module</b>. -X -<p>The basic plan is to wrap your <b>Task</b> into a <b>Module</b>, push -the <b>Module</b> onto the <b>Stream</b>. Do this for each <b>Task</b>, -X and then inject <b>Message_Block</b>s into the <b>Stream</b>. -X -<p>Each <b>Task</b> then processes the <b>Message_Block</b>, and forwards -it on to the next <b>Task</b> in the <b>Stream</b>. -X -<p>If you are not already familiar with <b>Message_Block</b>s and <b>Message_Queue</b>s, -I highly suggest that you check out <A HREF="../#MQ">Tutorials 10-13</A>. -X -<p>Streams can be used for both downstream and upstream movement of messages. Used -this way mirrors closely the way System V STREAMS work. But you don't have to use them -bidirectionally. In this tutorial, we only use one direction of the Stream. Down. -X -<p>This tutorial is contributed by Bob McWhirter (bob@netwrench.com) -<P> -SHAR_EOF - $shar_touch -am 1012190598 'page01.pre' && - chmod 0644 'page01.pre' || - $echo 'restore of' 'page01.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page01.pre:' 'MD5 check failed' -5b2cf5b57c135827e8465cdcfc83357f page01.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`" - test 1023 -eq "$shar_count" || - $echo 'page01.pre:' 'original size' '1023,' 'current size' "$shar_count!" - fi -fi -# ============= page02.pre ============== -if test -f 'page02.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page02.pre' '(file already exists)' -else - $echo 'x -' extracting 'page02.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page02.pre' && -<P> -You find pretty soon that anytime you work with ACE_Task<> you -X have to create a derivative. The Task.h header simply provides -X that derivative with the overrides we'll need in our application. -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 1012190598 'page02.pre' && - chmod 0644 'page02.pre' || - $echo 'restore of' 'page02.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page02.pre:' 'MD5 check failed' -4568ed757f3dbc1cebb7dc10d4768894 page02.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`" - test 231 -eq "$shar_count" || - $echo 'page02.pre:' 'original size' '231,' 'current size' "$shar_count!" - fi -fi -# ============= page03.pre ============== -if test -f 'page03.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page03.pre' '(file already exists)' -else - $echo 'x -' extracting 'page03.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page03.pre' && -<P> -Before we get to main() let's take a look at the Task implementation. -X While we've overridden several methods, the real work is done in -X the close() and svc() methods. -<P> -Notice how close() figures out if it is being called by the shutdown -X of the ACE_Stream or by the exit of svc(). The magic here is -X provided by the <i>flags</i> parameter. By handling the stream -X shutdown in this way, we don't have to do anything strange in -X svc(). We also don't end up with extra hangup messages in the -X queue when the dust all settles down. -<P> -Like our other tutorials, svc() looks for a hangup and processes data. -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 1012190598 'page03.pre' && - chmod 0644 'page03.pre' || - $echo 'restore of' 'page03.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page03.pre:' 'MD5 check failed' -5c35812c1251ef1e8214fa9d9a18d496 page03.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`" - test 651 -eq "$shar_count" || - $echo 'page03.pre:' 'original size' '651,' 'current size' "$shar_count!" - fi -fi -# ============= page04.pre ============== -if test -f 'page04.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page04.pre' '(file already exists)' -else - $echo 'x -' extracting 'page04.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page04.pre' && -<P> -As stated in the comments below, the default action of the task at the -X stream tail is to treat any received data as an error. In our -X implementation it will often happen that data gets through to -X the tail. How, then, do we handle this without creating an -X error condition? Simple: Create a custom Task for use as the -X stream tail that doesn't consider it an error to receive data. -<P> -Read on... -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 1012190598 'page04.pre' && - chmod 0644 'page04.pre' || - $echo 'restore of' 'page04.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page04.pre:' 'MD5 check failed' -c6eaa0dbd1216734dcf83f5283d433f3 page04.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`" - test 439 -eq "$shar_count" || - $echo 'page04.pre:' 'original size' '439,' 'current size' "$shar_count!" - fi -fi -# ============= page05.pre ============== -if test -f 'page05.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page05.pre' '(file already exists)' -else - $echo 'x -' extracting 'page05.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page05.pre' && -<P> -Now we come to main(). In the previous task-chain tutorial -X every thread pool had to have the same number of threads. This -X time around, we leverage the construction method of ACE_Stream -X and ACE_Module to customize the thread-pool size in each -X ACE_Task of the stream. -<P> -Remember EndTask from the previous page? We create one here and push -X it into the stream to take care of cleaning up the messages. -X Technically, we could have replaced the default Tail task -X created by the ACE framework but it seems to make more sense to -X just push our "tail" onto the stream like the other tasks. The -X caveat to this method is that you must be sure you don't push() -X any other Modules behind the EndTask! -<P> -Once the stream of modules containing tasks is all setup then we can -X put() some data into the stream for processing. The clever use -X of Task::close() makes shutting downt the stream easier than -X ever. No messing with hangup messages at the application level, -X just close() when you're done! What could be simpler? -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 1012190598 'page05.pre' && - chmod 0644 'page05.pre' || - $echo 'restore of' 'page05.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page05.pre:' 'MD5 check failed' -e1c3ef1d521db6daf9e432fb5582607d page05.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`" - test 1079 -eq "$shar_count" || - $echo 'page05.pre:' 'original size' '1079,' 'current size' "$shar_count!" - fi -fi -rm -fr _sh14739 -exit 0 diff --git a/docs/tutorials/014/page01.html b/docs/tutorials/014/page01.html deleted file mode 100644 index ac4a0ea6d65..00000000000 --- a/docs/tutorials/014/page01.html +++ /dev/null @@ -1,38 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> - -<p><b>ACE_Stream</b> is handy when you have several <b>ACE_Task</b> objects -that you would like to link together. - -<p>An intermediate class you we will deal with is the <b>ACE_Module</b>. - -<p>The basic plan is to wrap your <b>Task</b> into a <b>Module</b>, push -the <b>Module</b> onto the <b>Stream</b>. Do this for each <b>Task</b>, - and then inject <b>Message_Block</b>s into the <b>Stream</b>. - -<p>Each <b>Task</b> then processes the <b>Message_Block</b>, and forwards -it on to the next <b>Task</b> in the <b>Stream</b>. - -<p>If you are not already familiar with <b>Message_Block</b>s and <b>Message_Queue</b>s, -I highly suggest that you check out <A HREF="../#MQ">Tutorials 10-13</A>. - -<p>Streams can be used for both downstream and upstream movement of messages. Used -this way mirrors closely the way System V STREAMS work. But you don't have to use them -bidirectionally. In this tutorial, we only use one direction of the Stream. Down. - -<p>This tutorial is contributed by Bob McWhirter (bob@netwrench.com) -<P> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/014/page02.html b/docs/tutorials/014/page02.html deleted file mode 100644 index fb1fd2c60ef..00000000000 --- a/docs/tutorials/014/page02.html +++ /dev/null @@ -1,92 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -<P> -You find pretty soon that anytime you work with ACE_Task<> you - have to create a derivative. The Task.h header simply provides - that derivative with the overrides we'll need in our application. -<P> -<HR WIDTH="100%"> -<PRE> - -<font color=red>// $Id$</font> - -<font color=red>// Task.h</font> -<font color=red>//</font> -<font color=red>// Tutorial regarding a way to use ACE_Stream.</font> -<font color=red>//</font> -<font color=red>// written by bob mcwhirter (bob@netwrench.com)</font> -<font color=red>//</font> -<font color=red>//</font> - -<font color=blue>#ifndef</font> <font color=purple>TASK_H</font> -<font color=blue>#define</font> <font color=purple>TASK_H</font> - -<font color=blue>#include</font> <ace/Task.h> -<font color=blue>#include</font> <ace/Synch.h> - -<font color=red>// Always typedef when possible.</font> - -typedef ACE_Task<ACE_MT_SYNCH> Task_Base; - -class Task : public Task_Base -{ - -public: - - typedef Task_Base inherited; - <font color=red>// This is just good form.</font> - - Task(const char *nameOfTask, - int numberOfThreads); - <font color=red>// Initialize our Task with a name,</font> - <font color=red>// and number of threads to spawn.</font> - - virtual ~Task(void); - - virtual int open(void *arg); - <font color=red>// This is provided to prevent compiler complaints</font> - <font color=red>// about hidden virtual functions.</font> - - virtual int close(u_long flags); - <font color=red>// This closes down the Task and all service threads.</font> - - virtual int put(ACE_Message_Block *message, - ACE_Time_Value *timeout); - <font color=red>// This is the interface that ACE_Stream uses to</font> - <font color=red>// communicate with our Task.</font> - - virtual int svc(void); - <font color=red>// This is the actual service loop each of the service</font> - <font color=red>// threads iterates through.</font> - - const char *nameOfTask(void) const; - <font color=red>// Returns the name of this Task.</font> - -private: - - int d_numberOfThreads; - char d_nameOfTask[64]; - - ACE_Barrier d_barrier; - <font color=red>// Simple Barrier to make sure all of our service</font> - <font color=red>// threads have entered their loop before accepting</font> - <font color=red>// any messages.</font> -}; - - -<font color=blue>#endif</font> <font color=red>// TASK_H</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/014/page03.html b/docs/tutorials/014/page03.html deleted file mode 100644 index 6656fef56d7..00000000000 --- a/docs/tutorials/014/page03.html +++ /dev/null @@ -1,243 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -<P> -Before we get to main() let's take a look at the Task implementation. - While we've overridden several methods, the real work is done in - the close() and svc() methods. -<P> -Notice how close() figures out if it is being called by the shutdown - of the ACE_Stream or by the exit of svc(). The magic here is - provided by the <i>flags</i> parameter. By handling the stream - shutdown in this way, we don't have to do anything strange in - svc(). We also don't end up with extra hangup messages in the - queue when the dust all settles down. -<P> -Like our other tutorials, svc() looks for a hangup and processes data. -<P> -<HR WIDTH="100%"> -<PRE> - -<font color=red>// $Id$</font> - -<font color=red>// Task.cxx</font> -<font color=red>//</font> -<font color=red>// Tutorial regarding a way to use ACE_Stream.</font> -<font color=red>//</font> -<font color=red>// written by bob mcwhirter (bob@netwrench.com)</font> -<font color=red>//</font> -<font color=red>//</font> - -<font color=blue>#include</font> <ace/Message_Block.h> - -<font color=blue>#include</font> "<font color=green>Task.h</font>" - -<font color=#008888>Task::Task</font>(const char * nameOfTask, - int numberOfThreads) - : d_numberOfThreads(numberOfThreads), - d_barrier(numberOfThreads) -{ - <font color=red>// Just initialize our name, number of threads, and barrier.</font> - - <font color=#008888>ACE_OS::strcpy</font>(d_nameOfTask, nameOfTask); -} - -<font color=#008888>Task::~Task</font>(void) -{ - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) %s <font color=#008888>Task::~Task</font>() -- once per Task\n</font>", d_nameOfTask)); -} - -int <font color=#008888>Task::open</font>(void *arg) -{ - ACE_UNUSED_ARG(arg); - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) %s <font color=#008888>Task::open</font>() -- once per Task\n</font>", d_nameOfTask)); - - <font color=red>// call <font color=#008888>ACE_Task::activate</font>() to spawn the threads using</font> - <font color=red>// our <font color=#008888>Task::svc</font>() as the function to be run.</font> - - <font color=red>// FMM -- Frequently Made Mistake --</font> - <font color=red>// </font> - <font color=red>// If you specify the flag THR_DETACHED when activating the</font> - <font color=red>// Task, you will get an assert() violation during close(),</font> - <font color=red>// since the Task waits for all of its threads to rejoin.</font> - <font color=red>// </font> - - return this->activate(THR_NEW_LWP, d_numberOfThreads); -} - -int <font color=#008888>Task::put</font>(ACE_Message_Block *message, - ACE_Time_Value *timeout) -{ - <font color=red>// ACE_Stream uses the put() method of Tasks to send messages.</font> - <font color=red>// This defaultly does nothing. Here we link our put() method</font> - <font color=red>// directly to our putq() method, so that Messages put() to us</font> - <font color=red>// will appear in the Message_Queue that is checked by the</font> - <font color=red>// service threads.</font> - - return this->putq(message, timeout); -} - -int <font color=#008888>Task::close</font>(u_long flags) -{ - - <font color=red>// When the Stream closes the Module, the Module then close()'s the Task</font> - <font color=red>// and passing a value of (1) as the flag.</font> - - <font color=red>// When a service thread exits, it calls close() with a value that is not</font> - <font color=red>// (1).</font> - - <font color=red>// We use this fact to tell the difference between closing a service thread,</font> - <font color=red>// and closing the main Task itself.</font> - - if (flags == 1) { - - <font color=red>// The Module has asked to close the main Task.</font> - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) %s <font color=#008888>Task::close</font>() -- flags == 1 -- once per Task\n</font>", d_nameOfTask)); - - <font color=red>// We create a Message_Block...</font> - - ACE_Message_Block *hangupBlock = new ACE_Message_Block(); - - <font color=red>// And make it of the type MB_HANGUP. </font> - - hangupBlock->msg_type(<font color=#008888>ACE_Message_Block::MB_HANGUP</font>); - - <font color=red>// We then send this Block into the Message_Queue to be seen by the </font> - <font color=red>// service threads.</font> - - <font color=red>// Once again we duplicate() the Block as send it off...</font> - - if (this->putq(hangupBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Task::close</font>() putq</font>"), -1); - } - - <font color=red>// ..and we're free to release() our copy of it.</font> - - hangupBlock->release(); - - <font color=red>// Now, all we have to do is wait() for the service threads to all </font> - <font color=red>// exit. This is where using THR_DETACHED in the activate() method</font> - <font color=red>// will come back to haunt you.</font> - - <font color=red>// The Stream waits until this returns before attempting to remove</font> - <font color=red>// the next Module/Task group in the Stream. This allows for an</font> - <font color=red>// orderly shutting down of the Stream.</font> - - return this->wait(); - - - } else { - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) %s <font color=#008888>Task::close</font>() -- flags != 1 -- once per servicing thread\n</font>", d_nameOfTask)); - - <font color=red>// This is where we can clean up any mess left over by each service thread.</font> - <font color=red>// In this Task, there is nothing to do.</font> - - } - - return 0; - -} - -int <font color=#008888>Task::svc</font>(void) -{ - - <font color=red>// This is the function that our service threads run once they are spawned.</font> - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) %s <font color=#008888>Task::svc</font>() -- once per servicing thread\n</font>", d_nameOfTask)); - - <font color=red>// First, we wait until all of our peer service threads have arrived</font> - <font color=red>// at this point also.</font> - - d_barrier.wait(); - - ACE_Message_Block *messageBlock; - - while (1) { - - <font color=red>// And now we loop almost infinitely.</font> - - <font color=red>// getq() will block until a Message_Block is available to be read,</font> - <font color=red>// or an error occurs.</font> - - if ( this->getq(messageBlock, 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Task::svc</font>() getq</font>"), -1); - } - - if (messageBlock->msg_type() == <font color=#008888>ACE_Message_Block::MB_HANGUP</font>) { - - <font color=red>// If the Message_Block is of type MB_HANGUP, then we're being asked</font> - <font color=red>// to shut down nicely.</font> - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) %s <font color=#008888>Task::svc</font>() -- HANGUP block received\n</font>", d_nameOfTask)); - - <font color=red>// So, we duplicate the Block, and put it back into the Message_Queue,</font> - <font color=red>// in case there are some more peer service threads still running.</font> - - if (this->putq(messageBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Task::svc</font>() putq</font>"), -1); - } - - <font color=red>// We release our copy of the Block.</font> - messageBlock->release(); - - <font color=red>// And we break out of the nearly infinitely loop, and</font> - <font color=red>// head towards close() ourselves.</font> - break; - } - - <font color=red>// If we're here, then we've received a Message_Block that was </font> - <font color=red>// not informing us to quit, so we're assuming it's a valid</font> - <font color=red>// meaningful Block.</font> - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) %s <font color=#008888>Task::svc</font>() -- Normal block received\n</font>", d_nameOfTask)); - - <font color=red>// We grab the read-pointer from the Block, and display it through a DEBUG statement.</font> - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) %s <font color=#008888>Task::svc</font>() -- %s\n</font>", d_nameOfTask, messageBlock->rd_ptr() )); - - <font color=red>// We pretend that this takes to time to process the Block.</font> - <font color=red>// If you're on a fast machine, you might have to raise this</font> - <font color=red>// value to actually witness different threads handling</font> - <font color=red>// blocks for each Task.</font> - - <font color=#008888>ACE_OS::sleep</font> (ACE_Time_Value (0, 250)); - - <font color=red>// Since we're part of a Stream, we duplicate the Block, and </font> - <font color=red>// send it on to the next Task.</font> - - if (put_next(messageBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Task::svc</font>() put_next</font>"), -1); - } - - <font color=red>// And then we release our copy of it.</font> - - messageBlock->release(); - - } - - return 0; - -} - - -const char * <font color=#008888>Task::nameOfTask</font>(void) const -{ - return d_nameOfTask; -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/014/page04.html b/docs/tutorials/014/page04.html deleted file mode 100644 index 88b6c553d0b..00000000000 --- a/docs/tutorials/014/page04.html +++ /dev/null @@ -1,109 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -<P> -As stated in the comments below, the default action of the task at the - stream tail is to treat any received data as an error. In our - implementation it will often happen that data gets through to - the tail. How, then, do we handle this without creating an - error condition? Simple: Create a custom Task for use as the - stream tail that doesn't consider it an error to receive data. -<P> -Read on... -<P> -<HR WIDTH="100%"> -<PRE> - -<font color=red>// $Id$</font> - -<font color=red>// EndTask.h</font> -<font color=red>//</font> -<font color=red>// Tutorial regarding a way to use ACE_Stream.</font> -<font color=red>//</font> -<font color=red>// written by bob mcwhirter (bob@netwrench.com)</font> -<font color=red>//</font> -<font color=red>//</font> - -<font color=blue>#ifndef</font> <font color=purple>ENDTASK_H</font> -<font color=blue>#define</font> <font color=purple>ENDTASK_H</font> - -<font color=blue>#include</font> "<font color=green>Task.h</font>" - -<font color=red>// When you setup a Stream and push your modules on,</font> -<font color=red>// there are two additional modules that go unseen</font> -<font color=red>// by the user.</font> -<font color=red>//</font> -<font color=red>// The Stream pushes on a Stream_Head in front of</font> -<font color=red>// your first module, and a Stream_Tail behind your</font> -<font color=red>// last module.</font> -<font color=red>//</font> -<font color=red>// If your put() a message to the Stream Tail, it</font> -<font color=red>// assumes you did so in error. This simple EndTask</font> -<font color=red>// class allows you to push a message to it and just</font> -<font color=red>// have it safely Go Away.</font> -<font color=red>//</font> -<font color=red>// All this Task does is release the Message_Block</font> -<font color=red>// and return 0. It's a suitable black-hole.</font> - - -class EndTask : public Task -{ - -public: - - typedef Task inherited; - - EndTask(const char *nameOfTask) : - inherited(nameOfTask, 0) { - - <font color=red>// when we get open()'d, it with 0 threads</font> - <font color=red>// since there is actually no processing to do.</font> - - cerr << __LINE__ << "<font color=green> </font>" << __FILE__ << endl; - }; - - virtual int open(void *) - { - cerr << __LINE__ << "<font color=green> </font>" << __FILE__ << endl; - return 0; - } - - virtual int open(void) - { - cerr << __LINE__ << "<font color=green> </font>" << __FILE__ << endl; - return 0; - } - - virtual ~EndTask(void) { - }; - - virtual int put(ACE_Message_Block *message, - ACE_Time_Value *timeout) { - - cerr << __LINE__ << "<font color=green> </font>" << __FILE__ << endl; - ACE_UNUSED_ARG(timeout); - - <font color=red>// we don't have anything to do, so</font> - <font color=red>// release() the message.</font> - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) %s <font color=#008888>EndTask::put</font>() -- releasing Message_Block\n</font>", this->nameOfTask())); - message->release(); - return 0; - }; - -}; - -<font color=blue>#endif</font> <font color=red>// ENDTASK_H</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/014/page05.html b/docs/tutorials/014/page05.html deleted file mode 100644 index 8762651b89c..00000000000 --- a/docs/tutorials/014/page05.html +++ /dev/null @@ -1,215 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -<P> -Now we come to main(). In the previous task-chain tutorial - every thread pool had to have the same number of threads. This - time around, we leverage the construction method of ACE_Stream - and ACE_Module to customize the thread-pool size in each - ACE_Task of the stream. -<P> -Remember EndTask from the previous page? We create one here and push - it into the stream to take care of cleaning up the messages. - Technically, we could have replaced the default Tail task - created by the ACE framework but it seems to make more sense to - just push our "tail" onto the stream like the other tasks. The - caveat to this method is that you must be sure you don't push() - any other Modules behind the EndTask! -<P> -Once the stream of modules containing tasks is all setup then we can - put() some data into the stream for processing. The clever use - of Task::close() makes shutting downt the stream easier than - ever. No messing with hangup messages at the application level, - just close() when you're done! What could be simpler? -<P> -<HR WIDTH="100%"> -<PRE> - -<font color=red>// $Id$</font> - -<font color=red>// stream.cxx</font> -<font color=red>//</font> -<font color=red>// Tutorial regarding a way to use ACE_Stream.</font> -<font color=red>//</font> -<font color=red>// written by bob mcwhirter (bob@netwrench.com)</font> -<font color=red>//</font> -<font color=red>//</font> - -<font color=blue>#include</font> "<font color=green>Task.h</font>" -<font color=blue>#include</font> "<font color=green>EndTask.h</font>" -<font color=red>// This is our specialized ACE_Task.</font> - -<font color=blue>#include</font> <ace/Module.h> -<font color=blue>#include</font> <ace/Stream.h> -<font color=red>// These are the neccessary ACE headers.</font> - - -typedef ACE_Module<ACE_MT_SYNCH> Module; -typedef ACE_Stream<ACE_MT_SYNCH> Stream; -<font color=red>// Just to avoid a lot of typing, typedefs</font> -<font color=red>// are generally a good idea.</font> - -int main(int argc, char *argv[]) -{ - cerr << __LINE__ << endl; - - int numberOfMessages = argc > 1 ? <font color=#008888>ACE_OS::atoi</font>(argv[1]) : 3; - <font color=red>// unless otherwise specified, just send three messages</font> - <font color=red>// down the stream.</font> - - Stream theStream; - <font color=red>// the ACE_Stream itself.</font> - - cerr << __LINE__ << endl; - - <font color=red>// Now, we instantiate 4 different Tasks. These do not</font> - <font color=red>// need to be all the same class, but they do need to</font> - <font color=red>// all derrive from the same flavor of ACE_Task.</font> - <font color=red>//</font> - <font color=red>// Also, we instantiate a fifth end-cap Task to clean</font> - <font color=red>// up Message_Blocks as they reach the end.</font> - - Task *taskOne; - Task *taskTwo; - Task *taskThree; - Task *taskFour; - Task *taskEnd; - - <font color=red>// Out Task's take two arguments: a name, and the number</font> - <font color=red>// of threads to dedicate to the task.</font> - - taskOne = new Task("<font color=green>Task No. 1</font>", 1); - taskTwo = new Task("<font color=green>Task No. 2</font>", 3); - taskThree = new Task("<font color=green>Task No. 3</font>", 7); - taskFour = new Task("<font color=green>Task No. 4</font>", 1); - - <font color=red>// Our EndTask only takes 1 argument, as it actually</font> - <font color=red>// doesn't spawn any threads for processing.</font> - - taskEnd = new EndTask("<font color=green>End Task</font>"); - - Module *moduleOne; - Module *moduleTwo; - Module *moduleThree; - Module *moduleFour; - Module *moduleEnd; - - <font color=red>// ACE_Stream accepts ACE_Modules, which are simply a pair of</font> - <font color=red>// ACE_Tasks. One is dedicated for writing, while the other</font> - <font color=red>// is dedicated to reading. Think of the writing side as</font> - <font color=red>// downstream, and the reading side as upstream.</font> - <font color=red>//</font> - <font color=red>// We're only working with a unidirection Stream today,</font> - <font color=red>// so we'll only actually install a Task into the write</font> - <font color=red>// side of the module, effectively downstream.</font> - - cerr << __LINE__ << endl; - moduleOne = new Module("<font color=green>Module No. 1</font>", taskOne); - moduleTwo = new Module("<font color=green>Module No. 2</font>", taskTwo); - moduleThree = new Module("<font color=green>Module No. 3</font>", taskThree); - moduleFour = new Module("<font color=green>Module No. 4</font>", taskFour); - moduleEnd = new Module("<font color=green>Module End</font>", taskEnd); - - cerr << __LINE__ << endl; - <font color=red>// Now we push the Modules onto the Stream.</font> - <font color=red>// Pushing adds the module to the head, or </font> - <font color=red>// otherwise prepends it to whatever modules</font> - <font color=red>// are already installed.</font> - - <font color=red>// So, you need to push() the modules on -backwards-</font> - <font color=red>// from our viewpoint.</font> - - if (theStream.push(moduleEnd) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>push</font>"), -1); - } - - cerr << __LINE__ << endl; - if (theStream.push(moduleFour) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>push</font>"), -1); - } - - <font color=red>// As we push a Module onto the Stream, it gets opened.</font> - <font color=red>// When a Module open()s, it opens the Tasks that it contains.</font> - <font color=red>//</font> - <font color=red>// Since we cannot provide an argument to this embedded</font> - <font color=red>// call to open(), we supplied specified the number of</font> - <font color=red>// threads in the constructor of our Tasks.</font> - - if (theStream.push(moduleThree) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>push</font>"), -1); - } - - if (theStream.push(moduleTwo) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>push</font>"), -1); - } - - if (theStream.push(moduleOne) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>push</font>"), -1); - } - - cerr << __LINE__ << endl; - <font color=red>// Now that the Modules are open, the Tasks threads should</font> - <font color=red>// be launching and entering their svc() loop, so we send</font> - <font color=red>// some messages down the Stream.</font> - - int sent = 1; - - ACE_Message_Block *message; - - while (sent <= numberOfMessages) { - - <font color=red>// First, create ourselves a Message_Block.</font> - <font color=red>// see Tutorials 10-13 for more information</font> - <font color=red>// about Message_Blocks and Message_Queues.</font> - - message = new ACE_Message_Block(128); - - <font color=red>// Now, we grab the write-pointer from the Block,</font> - <font color=red>// and sprintf() our text into it.</font> - - <font color=#008888>ACE_OS::sprintf</font>(message->wr_ptr(), "<font color=green>Message No. %d</font>", sent); - - <font color=red>// All we have to do now is drop the Message_Block</font> - <font color=red>// into the Stream.</font> - - <font color=red>// It is always a good idea to duplicate() a Message_Block</font> - <font color=red>// when you put it into any Message_Queue, as then</font> - <font color=red>// you can always be allowed to release() your copy</font> - <font color=red>// without worry.</font> - - if (theStream.put(message->duplicate(), 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>put</font>"), -1); - } - - message->release(); - ++sent; - } - - <font color=red>// Now that we've sent our Message_Blocks, close down</font> - <font color=red>// the Stream.</font> - <font color=red>//</font> - <font color=red>// The Stream will automagically delete the Modules and</font> - <font color=red>// the contained Tasks. We don't have to do that.</font> - <font color=red>//</font> - <font color=red>// This call will block (due to the way we've written our </font> - <font color=red>// Task class) until all Message_Blocks have cleared the</font> - <font color=red>// entire Stream, and all associated threads have exited.</font> - - theStream.close(); - - return 0; -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] </CENTER> diff --git a/docs/tutorials/014/page06.html b/docs/tutorials/014/page06.html deleted file mode 100644 index 01e5fef889c..00000000000 --- a/docs/tutorials/014/page06.html +++ /dev/null @@ -1,28 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="Bob McWhirter"> - <TITLE>ACE Tutorial 014</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 014</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>ACE_Stream Tutorial, Of Sorts</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> - -Ok, so that's the Stream tutorial. As you can see, it's much simpler - than the task-chain developed last time but at the same time it - is also much more extensible. - -<UL> -<LI><A HREF="Makefile">Makefile</A> -<LI><A HREF="Task.h">Task.h</A> -<LI><A HREF="Task.cpp">Task.cpp</A> -<LI><A HREF="EndTask.h">EndTask.h</A> -<LI><A HREF="stream.cpp">stream.cpp</A> -</UL> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] </CENTER> diff --git a/docs/tutorials/014/stream.cpp b/docs/tutorials/014/stream.cpp deleted file mode 100644 index 4925bd5cf10..00000000000 --- a/docs/tutorials/014/stream.cpp +++ /dev/null @@ -1,175 +0,0 @@ - -// $Id$ - -// stream.cxx -// -// Tutorial regarding a way to use ACE_Stream. -// -// written by bob mcwhirter (bob@netwrench.com) -// -// - -#include "Task.h" -#include "EndTask.h" -// This is our specialized ACE_Task. - -#include <ace/Module.h> -#include <ace/Stream.h> -// These are the neccessary ACE headers. - - -typedef ACE_Module<ACE_MT_SYNCH> Module; -typedef ACE_Stream<ACE_MT_SYNCH> Stream; -// Just to avoid a lot of typing, typedefs -// are generally a good idea. - -int main(int argc, char *argv[]) -{ - cerr << __LINE__ << endl; - - int numberOfMessages = argc > 1 ? ACE_OS::atoi(argv[1]) : 3; - // unless otherwise specified, just send three messages - // down the stream. - - Stream theStream; - // the ACE_Stream itself. - - cerr << __LINE__ << endl; - - // Now, we instantiate 4 different Tasks. These do not - // need to be all the same class, but they do need to - // all derrive from the same flavor of ACE_Task. - // - // Also, we instantiate a fifth end-cap Task to clean - // up Message_Blocks as they reach the end. - - Task *taskOne; - Task *taskTwo; - Task *taskThree; - Task *taskFour; - Task *taskEnd; - - // Out Task's take two arguments: a name, and the number - // of threads to dedicate to the task. - - taskOne = new Task("Task No. 1", 1); - taskTwo = new Task("Task No. 2", 3); - taskThree = new Task("Task No. 3", 7); - taskFour = new Task("Task No. 4", 1); - - // Our EndTask only takes 1 argument, as it actually - // doesn't spawn any threads for processing. - - taskEnd = new EndTask("End Task"); - - Module *moduleOne; - Module *moduleTwo; - Module *moduleThree; - Module *moduleFour; - Module *moduleEnd; - - // ACE_Stream accepts ACE_Modules, which are simply a pair of - // ACE_Tasks. One is dedicated for writing, while the other - // is dedicated to reading. Think of the writing side as - // downstream, and the reading side as upstream. - // - // We're only working with a unidirection Stream today, - // so we'll only actually install a Task into the write - // side of the module, effectively downstream. - - cerr << __LINE__ << endl; - moduleOne = new Module("Module No. 1", taskOne); - moduleTwo = new Module("Module No. 2", taskTwo); - moduleThree = new Module("Module No. 3", taskThree); - moduleFour = new Module("Module No. 4", taskFour); - moduleEnd = new Module("Module End", taskEnd); - - cerr << __LINE__ << endl; - // Now we push the Modules onto the Stream. - // Pushing adds the module to the head, or - // otherwise prepends it to whatever modules - // are already installed. - - // So, you need to push() the modules on -backwards- - // from our viewpoint. - - if (theStream.push(moduleEnd) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - cerr << __LINE__ << endl; - if (theStream.push(moduleFour) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - // As we push a Module onto the Stream, it gets opened. - // When a Module open()s, it opens the Tasks that it contains. - // - // Since we cannot provide an argument to this embedded - // call to open(), we supplied specified the number of - // threads in the constructor of our Tasks. - - if (theStream.push(moduleThree) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - if (theStream.push(moduleTwo) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - if (theStream.push(moduleOne) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "push"), -1); - } - - cerr << __LINE__ << endl; - // Now that the Modules are open, the Tasks threads should - // be launching and entering their svc() loop, so we send - // some messages down the Stream. - - int sent = 1; - - ACE_Message_Block *message; - - while (sent <= numberOfMessages) { - - // First, create ourselves a Message_Block. - // see Tutorials 10-13 for more information - // about Message_Blocks and Message_Queues. - - message = new ACE_Message_Block(128); - - // Now, we grab the write-pointer from the Block, - // and sprintf() our text into it. - - ACE_OS::sprintf(message->wr_ptr(), "Message No. %d", sent); - - // All we have to do now is drop the Message_Block - // into the Stream. - - // It is always a good idea to duplicate() a Message_Block - // when you put it into any Message_Queue, as then - // you can always be allowed to release() your copy - // without worry. - - if (theStream.put(message->duplicate(), 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "put"), -1); - } - - message->release(); - ++sent; - } - - // Now that we've sent our Message_Blocks, close down - // the Stream. - // - // The Stream will automagically delete the Modules and - // the contained Tasks. We don't have to do that. - // - // This call will block (due to the way we've written our - // Task class) until all Message_Blocks have cleared the - // entire Stream, and all associated threads have exited. - - theStream.close(); - - return 0; -} diff --git a/docs/tutorials/015/Client_i.cpp b/docs/tutorials/015/Client_i.cpp deleted file mode 100644 index 6415fed1966..00000000000 --- a/docs/tutorials/015/Client_i.cpp +++ /dev/null @@ -1,60 +0,0 @@ - -// $Id$ - -#include "Client_i.h" -#include "ace/Message_Block.h" -#include "ace/INET_Addr.h" -#include "ace/SOCK_Connector.h" - -// Simple constructor just remembers the endpoint information for use by open. -Client::Client( u_short _port, const char * _server) - : port_(_port), server_(_server) -{ - ; -} - -/* Do nothing. This should probably call close() if we can make sure - that it's OK to close() multiple times. -*/ -Client::~Client(void) -{ - ; -} - -/* Open the connection to the server. This is traditional ACE. We - simply construct an endpoint and use a connector to establish the - link. -*/ -int Client::open( void ) -{ - ACE_INET_Addr addr(port_,server_); - ACE_SOCK_Connector con; - - if( con.connect(peer(),addr) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "ACE_SOCK_Connector::connect()"), -1); - } - - // Something new here... We have to use the protocol stream - // to ensure that our data is in the correct format when - // received by the server. Thus, we open the stream and - // transfer ownership of the peer. - return stream().open( peer() ); -} - -// The remainder of the functions just delegate to the stream. - -int Client::close( void ) -{ - return stream().close(); -} - -int Client::put( ACE_Message_Block * _message ) -{ - return stream().put(_message,0); -} - -int Client::get( ACE_Message_Block * & _response ) -{ - return stream().get(_response); -} diff --git a/docs/tutorials/015/Client_i.h b/docs/tutorials/015/Client_i.h deleted file mode 100644 index c9f4e496bf2..00000000000 --- a/docs/tutorials/015/Client_i.h +++ /dev/null @@ -1,74 +0,0 @@ - -// $Id$ - -#ifndef CLIENT_H -#define CLIENT_H - -#include "ace/SOCK_Stream.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "Protocol_Stream.h" - -class ACE_Message_Block; - -/* Hide the details of connection and protocol-conformance from the - application-level logic. -*/ -class Client -{ -public: - // Provide the server information when constructing the - // object. This could (and probably should) be moved to the - // open() method. - Client( u_short _port, const char * _server ); - - // Cleanup... - ~Client(void); - - // Open the connection to the server. - int open(void); - - // Close the connection to the server. Be sure to do this - // before you let the Client go out of scope. - int close(void); - - // Put a message to the server. The Client assumes ownership - // of _message at that point and will release() it when done. - // Do not use _message after passing it to put(). - int put( ACE_Message_Block * _message ); - - // Get a response from the server. The caller becomes the - // owner of _response after this call and is responsible for - // invoking release() when done. - int get( ACE_Message_Block * & _response ); - -private: - // Protocol_Stream hides the protocol conformance details from - // us. - Protocol_Stream stream_; - - // We create a connection on the peer_ and then pass ownership - // of it to the protocol stream. - ACE_SOCK_Stream peer_; - - // Endpoing information saved by the constructor for use by open(). - u_short port_; - const char * server_; - - // Accessors for the complex member variables. - - Protocol_Stream & stream(void) - { - return this->stream_; - } - - ACE_SOCK_Stream & peer(void) - { - return this->peer_; - } -}; - -#endif // CLIENT_H diff --git a/docs/tutorials/015/Compressor.cpp b/docs/tutorials/015/Compressor.cpp deleted file mode 100644 index c2f796bd68e..00000000000 --- a/docs/tutorials/015/Compressor.cpp +++ /dev/null @@ -1,96 +0,0 @@ - -// $Id$ - -#include "Compressor.h" -#include "ace/SOCK_Stream.h" - -/* Construct our baseclass with the proper thread count. I really - should remove this option... - */ -Compressor::Compressor( int _thr_count ) - : inherited(_thr_count) -{ - ; -} - -Compressor::~Compressor(void) -{ - ; -} - -/* This is where you insert your compression code. Most compressors - want to work on a block of data instead of a byte-stream. - Fortunately the message block has a block that can be compressed. - Take a look at libz for a quick way to add compression to your - apps - */ -int Compressor::send(ACE_Message_Block *message, ACE_Time_Value *timeout) -{ - ACE_DEBUG ((LM_INFO, "(%P|%t) Compressor::send() compressing (%s)\n", message->rd_ptr() )); - - // Create a block to hold the compressed data. I belive libz - // recommends a buffer about 10-20% larger than the source. - // Other libraries/algorithms may have their own quirks. - ACE_Message_Block * compressed = new ACE_Message_Block( message->size() ); - - // Perform a bogus compression algorithm. 'CD' just tells me - // that this is compressed data and when we "decompress" we'll - // look for this signature to validate the data received. - ACE_OS::sprintf( compressed->wr_ptr(), "CD:%s", message->rd_ptr() ); - compressed->wr_ptr( strlen(compressed->wr_ptr())+1 ); - - // Send the compressed data down the stream to the next module - this->put_next( compressed ); - - // We're done here. - message->release(); - - return( 0 ); -} - -/* And here's the decompression side. We've written Xmit/Recv so that - we're guaranteed to get an entire block of compressed data. If - we'd used recv() in the Recv object then we might have gotten a - partial block and that may not decompress very nicely. - */ -int Compressor::recv(ACE_Message_Block *message, ACE_Time_Value *timeout) -{ - ACE_DEBUG ((LM_INFO, "(%P|%t) Compress::recv() decompressing (%s)\n", message->rd_ptr() )); - - // Room for the decompressed data. In the real world you - // would probably want to send the original (uncompressed) - // data size in the message. You can predict the maximum - // possible decompression size but it's cheap and easy just to - // send that along. Look again at how I do exacly that - // between Xmit and Recv. - ACE_Message_Block * decompressed = new ACE_Message_Block( message->size() ); - - // Check for our signature. Even when you use a real - // compression algorithm you may want to include your own - // signature so that you can verify the block. It pays to be - // paranoid! - if( ACE_OS::strncmp( message->rd_ptr(), "CD:", 3 ) ) - { - ACE_DEBUG ((LM_INFO, "(%P|%t) Improperly encompressed data.\n" )); - message->release(); - return(-1); - } - - // Skip past the signature before going any further. - message->rd_ptr( 3 ); - - // Perform a bogus decompression algorithm. This is where you - // would feed to libz or your favorite decompressor. (It's - // costly but you could invoke popen() on gzip!) - ACE_OS::sprintf( decompressed->wr_ptr(), "%s", message->rd_ptr() ); - decompressed->wr_ptr( strlen(decompressed->wr_ptr())+1 ); - - // Recv the decompressed data down the stream to the next module - this->put_next( decompressed ); - - // We're done here. - message->release(); - - return( 0 ); -} - diff --git a/docs/tutorials/015/Compressor.h b/docs/tutorials/015/Compressor.h deleted file mode 100644 index 4aaa83144ed..00000000000 --- a/docs/tutorials/015/Compressor.h +++ /dev/null @@ -1,43 +0,0 @@ - -// $Id$ - -#ifndef COMPRESSOR_H -#define COMPRESSOR_h - -#include "Protocol_Task.h" - -/* A reallly dumb compression object. (It actually adds 3 bytes to - every message block.) -*/ -class Compressor : public Protocol_Task -{ -public: - - typedef Protocol_Task inherited; - - // I've given you the option of creating this task derivative - // with a number of threads. In retro-spect that really isn't - // a good idea. Most client/server systems rely on requests - // and responses happening in a predicatable order. Introduce - // a thread pool and message queue and that ordering goes - // right out the window. In other words: Don't ever use the - // constructor parameter! - Compressor( int _thr_count = 0 ); - - ~Compressor(void); - -protected: - - // This is called when the compressor is on the downstream - // side. We'll take the message, compress it and move it - // along to the next module. - int send(ACE_Message_Block *message, - ACE_Time_Value *timeout); - - // This one is called on the upstream side. No surprise: we - // decompress the data and send it on up the stream. - int recv(ACE_Message_Block *message, - ACE_Time_Value *timeout); -}; - -#endif // COMPRESSOR_H diff --git a/docs/tutorials/015/Crypt.cpp b/docs/tutorials/015/Crypt.cpp deleted file mode 100644 index 1e20b8f5b42..00000000000 --- a/docs/tutorials/015/Crypt.cpp +++ /dev/null @@ -1,77 +0,0 @@ - -// $Id$ - -#include "Crypt.h" -#include "ace/SOCK_Stream.h" - -/* The expected constructor... - */ -Crypt::Crypt( int _thr_count ) - : inherited(_thr_count) -{ -} - -Crypt::~Crypt(void) -{ -} - -/* To send the data we'll apply a signature and encryption. - */ -int Crypt::send(ACE_Message_Block *message, ACE_Time_Value *timeout) -{ - ACE_DEBUG ((LM_INFO, "(%P|%t) Crypt::send() encrypting (%s)\n", message->rd_ptr() )); - - // I suspect that some encryptors might change the data size. - // It probably isn't safe to create a same-size destination buffer. - ACE_Message_Block * encrypted = new ACE_Message_Block( message->size() ); - - // Perform a bogus encryption algorithm and add our safety - // signature. Adding the original data size is also probably - // a good idea that I haven't encorporated here. - ACE_OS::sprintf( encrypted->wr_ptr(), "ED:%s", message->rd_ptr() ); - encrypted->wr_ptr( strlen(encrypted->wr_ptr())+1 ); - - // Send the encrypted data down the stream to the next module - this->put_next( encrypted ); - - // We're done here. - message->release(); - - return( 0 ); -} - -/* The upstream movement requires that we decrypt what the peer has - given us. -*/ -int Crypt::recv(ACE_Message_Block *message, ACE_Time_Value *timeout) -{ - ACE_DEBUG ((LM_INFO, "(%P|%t) Crypt::recv() decrypting (%s)\n", message->rd_ptr() )); - - // Create a destination for the decrypted data. The same - // block size caveat exists of course. - ACE_Message_Block * decrypted = new ACE_Message_Block( message->size() ); - - // Check the signature as expected. - if( ACE_OS::strncmp( message->rd_ptr(), "ED:", 3 ) ) - { - ACE_DEBUG ((LM_INFO, "(%P|%t) Improperly encrypted data.\n" )); - message->release(); - return(-1); - } - - // Don't forget to skip past the signature before decrypting - // or things will be quite exciting! - message->rd_ptr( 3 ); - - // Perform a bogus decryption algorithm - ACE_OS::sprintf( decrypted->wr_ptr(), "%s", message->rd_ptr() ); - decrypted->wr_ptr( strlen(decrypted->wr_ptr())+1 ); - - // Send the decrypted data down the stream to the next module - this->put_next( decrypted ); - - // We're done here. - message->release(); - - return( 0 ); -} diff --git a/docs/tutorials/015/Crypt.h b/docs/tutorials/015/Crypt.h deleted file mode 100644 index c7fb1d5948f..00000000000 --- a/docs/tutorials/015/Crypt.h +++ /dev/null @@ -1,35 +0,0 @@ - -// $Id$ - -#ifndef CRYPT_H -#define CRYPT_h - -#include "Protocol_Task.h" - -/* An interface (adaptor) between your favorite encryption method and - an ACE_Stream. -*/ -class Crypt : public Protocol_Task -{ -public: - - typedef Protocol_Task inherited; - - // Again we have the option of multiple threads and again I - // regret tempting folks to use it. - Crypt( int _thr_count = 0 ); - - ~Crypt(void); - -protected: - - // Moving downstream will encrypt the data - int send(ACE_Message_Block *message, - ACE_Time_Value *timeout); - - // And moving upstream will decrypt it. - int recv(ACE_Message_Block *message, - ACE_Time_Value *timeout); -}; - -#endif // CRYPT_H diff --git a/docs/tutorials/015/Handler.cpp b/docs/tutorials/015/Handler.cpp deleted file mode 100644 index ab141c7e8c2..00000000000 --- a/docs/tutorials/015/Handler.cpp +++ /dev/null @@ -1,179 +0,0 @@ - -// $Id$ - -#include "Handler.h" -#include "Protocol_Task.h" - -/* The Protocol_Stream gives us the option to insert a Protocol_Task - to process data received by the stream. We'll get into the details - more when we talk about the stream in detail. For now it's enough - to know that Handler_Task::recv() will be invoked by the stream - after data from the client has been received and processed (eg -- - decrypted, uncompressed, and whatever else the protocol requires.) -*/ -class Handler_Task : public Protocol_Task -{ -public: - - // Typical... - typedef Protocol_Task inherited; - - // Simple... - Handler_Task(void); - ~Handler_Task(void); - -protected: - - // recv() is invoked after received data has been fully - // processed by the protocol rules. Data processing typically - // done in handle_input() can then be done here. - int recv(ACE_Message_Block * message, - ACE_Time_Value *timeout = 0); -}; - -Handler::Handler(void) -{ - ; -} - -Handler::~Handler(void) -{ - ; -} - -/* The Acceptor will open() us once the peer() connection is - established. There are a couple of things we have to do here - before we're ready to receive data from the client. -*/ -int Handler::open (void *) -{ - ACE_INET_Addr addr; - - // Make sure that we can get the peer's address. If we can't - // then there may be a network error or something else that - // will prevent communicating with the client. This is - // something you'll want to do in every event handler you create. - if (this->peer ().get_remote_addr (addr) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't get remote addr\n"), -1); - - // Announce the client - ACE_DEBUG ((LM_DEBUG, "(%P|%t) connected with %s\n", addr.get_host_name() )); - - // Here's the first new twist to the old event handler. - // Before we can use the Protocol_Stream to communicate with - // the peer, we must open() it. We provide the stream with - // the peer() so that it will have a valid socket on which to - // read client requests and send our responses. We also - // provide a Handler_Task instance that will ultimately be - // responsible for processing any client data we receive. - int rval = stream().open( this->peer(), new Handler_Task() ); - - // Of course, we have to account for the chance that the - // stream's open() may fail. - if( rval == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't open the protocol stream.\n"), -1); - } - - // Now that we know the client is valid and that the stream is - // ready for business we can register with the gloabl reactor - // instance. Here again is an opportunity for improvement if - // we expect to have mulitple Server object instances. - if (ACE_Reactor::instance()->register_handler (this, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1); - - return rval; -} - -/* This is a fairly typical destroy() method that can be shared by - both close() and handle_close(). -*/ -void Handler::destroy (void) -{ - ACE_Reactor::instance()->remove_handler(this,ACE_Event_Handler::READ_MASK|ACE_Event_Handler::DONT_CALL); - - this->peer ().close (); - - delete this; -} - -/* In this simple application we just forward the close() and - handle_close() requests right on to the destroy() method. -*/ - -int Handler::close (u_long) -{ - this->destroy (); - return 0; -} - -int Handler::handle_close(ACE_HANDLE, ACE_Reactor_Mask _mask) -{ - this->destroy(); - return 0; -} - -/* Unlike a "traditional" handle_input() ours is very simple. Because - of the use of the protocol stream, we delegate the read function to - the stream's get() and rely on our Handler_Task to do the real work. -*/ -int Handler::handle_input (ACE_HANDLE) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Activity from client\n" )); - - // This will cause a blocking read from the peer(). The data - // will then be pushed through the protocol stream. - if( stream().get( ) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) can't get data from protocol stream\n"), -1); - } - - return 0; -} - -/* A Protocol_Task is derived from ACE_Task and has the option of - running in one or more threads. I've chosen here to construct the - baseclass with no threads but it should work just fine with one or - more if you need. Unless you're sharing the Handler_Task with - several peers, however, you're probably just wasting a thread to - activate it. On the other hand, if your reactor is running in a - single thread (as in this example) then you can easily implement - thread-per-connectin concurrency by giving the baseclass one thread. -*/ -Handler_Task::Handler_Task(void) - : inherited(0) -{ - ; -} - -Handler_Task::~Handler_Task(void) -{ - ; -} - -/* When installed into the protocol stream, the Handler_Task's recv() - method will be called when data is ready for processing. - */ -int Handler_Task::recv(ACE_Message_Block * message, - ACE_Time_Value *timeout ) -{ - // Announce the request we got from the client - ACE_DEBUG ((LM_INFO, "(%P|%t) Handler_Task::recv() got (%s)\n", message->rd_ptr() )); - - // Create a response message to send to the client - ACE_Message_Block * response = new ACE_Message_Block( 128 ); - - // Nothing very original about this I'm afraid... - ACE_OS::sprintf( response->wr_ptr(), "You Said: (%s)", message->rd_ptr() ); - response->wr_ptr( strlen(response->wr_ptr())+1 ); - - // Release the original message block now that we're through - // "processing" it. - message->release(); - - // Turn the message around and send it back down the Stream. - // In other words, we invoke the put() method on the - // Protocol_Stream without having to have a direct reference - // to the stream object. - return this->reply( response, timeout ); -} diff --git a/docs/tutorials/015/Handler.h b/docs/tutorials/015/Handler.h deleted file mode 100644 index 73aa2573b0c..00000000000 --- a/docs/tutorials/015/Handler.h +++ /dev/null @@ -1,66 +0,0 @@ - -// $Id$ - -#ifndef HANDLER_H -#define HANDLER_H - -#include "ace/Svc_Handler.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "ace/SOCK_Stream.h" -#include "Protocol_Stream.h" - -/* Just your basic event handler. We use ACE_Svc_Handler<> as a - baseclass so that it can maintain the peer() and other details for - us. We're not going to activate() this object, so we can get away - with the NULL synch choice. -*/ -class Handler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > -{ -public: - - Handler(void); - ~Handler(void); - - // Called by the acceptor when we're created in response to a - // client connection. - int open (void *); - - // Called when it's time for us to be deleted. We take care - // of removing ourselves from the reactor and shutting down - // the peer() connectin. - void destroy (void); - - // Called when it's time for us to go away. There are subtle - // differences between destroy() and close() so don't try to - // use either for all cases. - int close (u_long); - -protected: - - // Respond to peer() activity. - int handle_input (ACE_HANDLE); - - // This will be called when handle_input() returns a failure - // code. That's our signal that it's time to begin the - // shutdown process. - int handle_close(ACE_HANDLE, ACE_Reactor_Mask _mask); - -private: - - // Like the Client, we have to abide by the protocol - // requirements. We use a local Protocol_Stream object to - // take care of those details. For us, I/O then just becomes - // a matter of interacting with the stream. - Protocol_Stream stream_; - - Protocol_Stream & stream(void) - { - return this->stream_; - } -}; - -#endif // HANDLER_H diff --git a/docs/tutorials/015/Makefile b/docs/tutorials/015/Makefile deleted file mode 100644 index 60733fb4e87..00000000000 --- a/docs/tutorials/015/Makefile +++ /dev/null @@ -1,30 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = client server - -all clean realclean : # - $(MAKE) -f Makefile.client $@ - $(MAKE) -f Makefile.server $@ - -client server : # - $(MAKE) -f Makefile.$@ all - -Depend : # - $(MAKE) -f Makefile.client $@ - -HTML : # - [ -f hdr ] || $(MAKE) UNSHAR - perl ../combine *.pre - chmod +r *.html - -SHAR : # - [ ! -f combine.shar ] || exit 1 - shar -T hdr bodies *.pre *.pst > combine.shar && rm -f hdr bodies *.pre *.pst - -UNSHAR : # - sh combine.shar diff --git a/docs/tutorials/015/Makefile.client b/docs/tutorials/015/Makefile.client deleted file mode 100644 index 20680aea15b..00000000000 --- a/docs/tutorials/015/Makefile.client +++ /dev/null @@ -1,79 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = client - -FILES += Protocol_Stream -FILES += Protocol_Task -FILES += Xmit -FILES += Recv -FILES += Compressor -FILES += Crypt -FILES += Client_i - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) -SRC += $(addsuffix .cpp,$(FILES)) - -HDR = *.h - -MAKEFILE = Makefile.client -DEPEND = .depend.client - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.lib.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -HTML : # - perl ../combine *.html - -rename : # - for i in *.cxx ; do \ - n=`expr "$$i" : "\(.*\).cxx"` ;\ - mv $$i $$n.cpp ;\ - done - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../fix.Makefile -f $(MAKEFILE) -o $(DEPEND) - -$(DEPEND) : - touch $(DEPEND) - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include $(DEPEND) -include .depend.client diff --git a/docs/tutorials/015/Makefile.server b/docs/tutorials/015/Makefile.server deleted file mode 100644 index 109cecc8e90..00000000000 --- a/docs/tutorials/015/Makefile.server +++ /dev/null @@ -1,81 +0,0 @@ - -# $Id$ - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -BIN = server - -FILES += Protocol_Stream -FILES += Protocol_Task -FILES += Xmit -FILES += Recv -FILES += Compressor -FILES += Crypt - -FILES += Handler -FILES += Server_i - -BUILD = $(VBIN) - -SRC = $(addsuffix .cpp,$(BIN)) -SRC += $(addsuffix .cpp,$(FILES)) - -HDR = *.h - -MAKEFILE = Makefile.server -DEPEND = .depend.server - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.lib.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - -HTML : # - perl ../combine *.html - -rename : # - for i in *.cxx ; do \ - n=`expr "$$i" : "\(.*\).cxx"` ;\ - mv $$i $$n.cpp ;\ - done - -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb -ts2 -bl -bli0 < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - -e 's/ / /g' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - -Depend : depend - perl ../fix.Makefile -f $(MAKEFILE) -o $(DEPEND) - -$(DEPEND) : - touch $(DEPEND) - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - -include $(DEPEND) -include .depend.server diff --git a/docs/tutorials/015/Protocol_Stream.cpp b/docs/tutorials/015/Protocol_Stream.cpp deleted file mode 100644 index 058ec300b2d..00000000000 --- a/docs/tutorials/015/Protocol_Stream.cpp +++ /dev/null @@ -1,171 +0,0 @@ - -// $Id$ - -#include "Protocol_Stream.h" -#include "Protocol_Task.h" - -#include "Xmit.h" -#include "Recv.h" - -#include "Compressor.h" -#include "Crypt.h" - -#include "ace/Stream_Modules.h" - -/* You can choose at compile time to include/exclude the protocol - pieces. -*/ -#define ENABLE_COMPRESSION -#define ENABLE_ENCRYPTION - -// The usual typedefs to make things easier to type. -typedef ACE_Module<ACE_MT_SYNCH> Module; -typedef ACE_Thru_Task<ACE_MT_SYNCH> Thru_Task; - -/* Do-nothing constructor and destructor - */ - -Protocol_Stream::Protocol_Stream( void ) -{ - ; -} - -Protocol_Stream::~Protocol_Stream( void ) -{ - ; -} - -/* Even opening the stream is rather simple. The important thing to - rememer is that the modules you push onto the stream first will be - at the tail (eg -- most downstream) end of things when you're - done. - */ -int Protocol_Stream::open( ACE_SOCK_Stream & _peer, Protocol_Task * _reader ) -{ - // Initialize our peer() to read/write the socket we're given - peer_.set_handle( _peer.get_handle() ); - - // Construct (and remember) the Recv object so that we can - // read from the peer(). - recv_ = new Recv( peer() ); - - // Add the transmit and receive tasks to the head of the - // stream. As we add more modules these will get pushed - // downstream and end up nearest the tail by the time we're - // done. - if( stream().push( new Module( "Xmit/Recv", new Xmit( peer() ), recv_ ) ) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "stream().push( xmit/recv )"), -1); - } - - // Add any other protocol tasks to the stream. Each one is - // added at the head. The net result is that Xmit/Recv are at - // the tail. - if( this->open() == -1 ) - { - return(-1); - } - - // If a reader task was provided then push that in as the - // upstream side of the next-to-head module. Any data read - // from the peer() will be sent through here last. Server - // applications will typically use this task to do the actual - // processing of data. - // Note the use of Thru_Task. Since a module must always have - // a pair of tasks we use this on the writter side as a no-op. - if( _reader ) - { - if( stream().push( new Module( "Reader", new Thru_Task(), _reader ) ) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "stream().push( reader )"), -1); - } - } - - return(0); -} - -/* Add the necessary protocol objects to the stream. The way we're - pushing things on we will encrypt the data before compressing it. -*/ -int Protocol_Stream::open(void) -{ -#if defined(ENABLE_COMPRESSION) - if( stream().push( new Module( "compress", new Compressor(), new Compressor() ) ) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "stream().push( comprssor )"), -1); - } -#endif // ENABLE_COMPRESSION - -#if defined(ENABLE_ENCRYPTION) - if( stream().push( new Module( "crypt", new Crypt(), new Crypt() ) ) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "stream().push( crypt )"), -1); - } -#endif // ENABLE_ENCRYPTION - return( 0 ); -} - -// Closing the Protocol_Stream is as simple as closing the ACE_Stream. -int Protocol_Stream::close(void) -{ - return stream().close(); -} - -// Simply pass the data directly to the ACE_Stream. -int Protocol_Stream::put(ACE_Message_Block * & _message, ACE_Time_Value * _timeout ) -{ - return stream().put(_message,_timeout); -} - -/* Tell the Recv module to read some data from the peer and pass it - upstream. Servers will typically use this method in a - handle_input() method to tell the stream to get a client's request. -*/ -int Protocol_Stream::get(void) -{ - // If there is no Recv module, we're in big trouble! - if( ! recv_ ) - { - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) No Recv object!\n"), -1); - } - - // This tells the Recv module to go to it's peer() and read - // some data. Once read, that data will be pushed upstream. - // If there is a reader object then it will have a chance to - // process the data. If not, the received data will be - // available in the message queue of the stream head's reader - // object (eg -- stream().head()->reader()->msg_queue()) and - // can be read with our other get() method below. - if( recv_->get() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) Cannot queue read request\n"), -1); - } - - // For flexibility I've added an error() method to tell us if - // something bad has happened to the Recv object. - if( recv_->error() ) - { - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) Recv object error!\n"), -1); - } - - return(0); -} - -/* Take a message block off of the stream head reader's message - queue. If the queue is empty, use get() to read from the peer. - This is most often used by client applications. Servers will - generaly insert a reader that will prevent the data from getting - all the way upstream to the head. -*/ -int Protocol_Stream::get(ACE_Message_Block * & _response, ACE_Time_Value * _timeout ) -{ - if( stream().head()->reader()->msg_queue()->is_empty() ) - { - if( this->get() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) Cannot get data into the stream.\n"), -1); - } - } - - return stream().head()->reader()->getq(_response,_timeout); -} diff --git a/docs/tutorials/015/Protocol_Stream.h b/docs/tutorials/015/Protocol_Stream.h deleted file mode 100644 index 686d39126e0..00000000000 --- a/docs/tutorials/015/Protocol_Stream.h +++ /dev/null @@ -1,86 +0,0 @@ - -// $Id$ - -#ifndef PROTOCOL_STREAM_H -#define PROTOCOL_STREAM_H - -#include "ace/SOCK_Stream.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "ace/Stream.h" - -// Shorthand for the stream. -typedef ACE_Stream<ACE_MT_SYNCH> Stream; - -// Forward references to cut down on the number of #includes -class ACE_Message_Block; -class Recv; -class Protocol_Task; - -/* The Protocol_Stream provides a tidy interface to an ACE_Stream - setup to process a data block through a series of protocol stages. -*/ -class Protocol_Stream -{ -public: - Protocol_Stream(void); - ~Protocol_Stream(void); - - // Provide the stream with an ACE_SOCK_Stream on which it can - // communicate. If _reader is non-null, it will be added as - // the reader task just below the stream head so that it can - // process data read from the peer. - int open( ACE_SOCK_Stream & _peer, Protocol_Task * _reader = 0 ); - - // Close the stream. All of the tasks & modules will also be closed. - int close(void); - - // putting data onto the stream will pass it through all - // protocol levels and send it to the peer. - int put( ACE_Message_Block * & _message, ACE_Time_Value * - _timeout = 0 ); - - // get will cause the Recv task (at the tail of the stream) to - // read some data from the peer and pass it upstream. The - // message block is then taken from the stream reader task's - // message queue. - int get( ACE_Message_Block * & _response, ACE_Time_Value * - _timeout = 0 ); - - // Tell the Recv task to read some data and send it upstream. - // The data will pass through the protocol tasks and be queued - // into the stream head reader task's message queue. If - // you've installed a _reader in open() then that task's - // recv() method will see the message and may consume it - // instead of passing it to the stream head for queueing. - int get(void); - - ACE_SOCK_Stream & peer(void) - { - return this->peer_; - } - -private: - // Our peer connection - ACE_SOCK_Stream peer_; - - // The stream managing the various protocol tasks - Stream stream_; - - // A task which is capable of receiving data on a socket. - // Note that this is only useful by client-side applications. - Recv * recv_; - - Stream & stream(void) - { - return this->stream_; - } - - // Install the protocol tasks into the stream. - int open(void); -}; - -#endif // PROTOCOL_STREAM_H diff --git a/docs/tutorials/015/Protocol_Task.cpp b/docs/tutorials/015/Protocol_Task.cpp deleted file mode 100644 index 3cfe7495539..00000000000 --- a/docs/tutorials/015/Protocol_Task.cpp +++ /dev/null @@ -1,146 +0,0 @@ - -// $Id$ - -#include "Protocol_Task.h" - -// Construct the object and remember the thread count. -Protocol_Task::Protocol_Task( int _thr_count ) - : desired_thr_count_(_thr_count) -{ -} - -Protocol_Task::~Protocol_Task(void) -{ -} - -// Activate the object if necessary. -int Protocol_Task::open(void *arg) -{ - ACE_UNUSED_ARG(arg); - - if( desired_thr_count_ ) - { - return this->activate(THR_NEW_LWP, desired_thr_count_); - } - - return(0); -} - -/* When we're being closed by the ACE_Stream and we've got threads to - worry about then we drop a hangup message onto the message queue so - that svc() will go away. Except for the call to is_active(), this - is lifted directly from Tutorial 14. -*/ -int Protocol_Task::close(u_long flags) -{ - if (flags == 1 && is_active() ) - { - ACE_Message_Block *hangupBlock = new ACE_Message_Block(); - - hangupBlock->msg_type(ACE_Message_Block::MB_HANGUP); - - if (this->putq(hangupBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Task::close() putq"), -1); - } - - hangupBlock->release(); - - return this->wait(); - } - - return 0; -} - -/* The put() method has to make a decision. If we've got threads then - put the unit of work onto the message queue for svc() to deal - with. If not then process() it directly. -*/ -int Protocol_Task::put(ACE_Message_Block *message,ACE_Time_Value *timeout) -{ - if( is_active() ) - { - return this->putq(message,timeout); - } - - return this->process(message,timeout); -} - -/* svc() is about what you would expect. This is again lifted - directly from Tutorial 14 but with a call to process() for handling - the logic instead of doing the work right here. - */ -int Protocol_Task::svc(void) -{ - ACE_Message_Block * message; - - while (1) - { - // Get a message - if ( this->getq(message, 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Protocol_Task::svc() getq"), -1); - } - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Protocol_Task::svc() got message\n")); - - // Check for hangup - if (message->msg_type() == ACE_Message_Block::MB_HANGUP) { - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) Protocol_Task::svc() -- HANGUP block received\n")); - - // Hangup our thread-pool peers (if any) - if (this->putq(message->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Protocol_Task::svc() putq"), -1); - } - - // Leave svc() - break; - } - - // Do some work on the data. - if( this->process(message->duplicate(),0) == -1 ) - { - break; - } - - // Give up the message block before we go get another. - message->release(); - } - - // Give up the message block that caused us to exit the - // while(1) loop. - message->release(); - - return(0); -} - -/* There's nothing really magic about process(). We just decide if - we're moving data upstream or downstream and invoke the appropriate - virtual function to handle it. -*/ -int Protocol_Task::process(ACE_Message_Block * message, ACE_Time_Value *timeout) -{ - if( this->is_writer() ) - { - return this->send(message,timeout); - } - - return this->recv(message,timeout); -} - -/* We must insist that derivatives provide a meaningful overload for - these methods. It's fairly common for ACE object methods to return - an error when an overload is expected but the method cannot be - safely made pure virtual. - */ - -int Protocol_Task::send(ACE_Message_Block *message, - ACE_Time_Value *timeout) -{ - return -1; -} - -int Protocol_Task::recv(ACE_Message_Block * message, - ACE_Time_Value *timeout) -{ - return -1; -} diff --git a/docs/tutorials/015/Protocol_Task.h b/docs/tutorials/015/Protocol_Task.h deleted file mode 100644 index 194809327ec..00000000000 --- a/docs/tutorials/015/Protocol_Task.h +++ /dev/null @@ -1,74 +0,0 @@ - -// $Id$ - -#ifndef PROTOCOL_TASK_H -#define PROTOCOL_TASK_H - -#include "ace/Task.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -/* A typical ACE_Task<> derivative that adds a few things appropriate - to protocol stacks. -*/ -class Protocol_Task : public ACE_Task<ACE_MT_SYNCH> -{ -public: - - typedef ACE_Task<ACE_MT_SYNCH> inherited; - - // A choice of concurrency strategies is offered by the - // constructor. In most cases it makes sense to set this to - // zero and let things proceed serially. You might have a - // need, however, for some of your tasks to have their own thread. - Protocol_Task( int _thr_count ); - - ~Protocol_Task(void); - - // open() is invoked when the task is inserted into the stream. - virtual int open(void *arg); - - // close() is invoked when the stream is closed (flags will be - // set to '1') and when the svc() method exits (flags will be - // '0'). - virtual int close(u_long flags); - - // As data travels through the stream, the put() method of - // each task is invoked to keep the data moving along. - virtual int put(ACE_Message_Block *message, - ACE_Time_Value *timeout); - - // If you choose to activate the task then this method will be - // doing all of the work. - virtual int svc(void); - -protected: - - // Called by put() or svc() as necessary to process a block of - // data. - int process(ACE_Message_Block * message, ACE_Time_Value *timeout); - - // Just let us know if we're active or not. - int is_active(void) - { - return this->thr_count() != 0; - } - - // Tasks on the writter (downstream) side of the stream - // are called upon to send() data that will ultimately go to - // the peer. - virtual int send(ACE_Message_Block *message, - ACE_Time_Value *timeout); - - // Tasks on the reader (upstream) side will be receiving data - // that came from the peer. - virtual int recv(ACE_Message_Block * message, - ACE_Time_Value *timeout); - -private: - int desired_thr_count_; -}; - -#endif // PROTOCOL_TASK_H diff --git a/docs/tutorials/015/Recv.cpp b/docs/tutorials/015/Recv.cpp deleted file mode 100644 index a8f284a76ef..00000000000 --- a/docs/tutorials/015/Recv.cpp +++ /dev/null @@ -1,85 +0,0 @@ - -// $Id$ - -#include "Recv.h" -#include "ace/SOCK_Stream.h" - -/* Construct the object with the peer reference and other appropriate - initializations. -*/ -Recv::Recv( ACE_SOCK_Stream & _peer ) - : inherited(0), peer_(_peer), error_(0) -{ - // Create the tickler that get() will use to trigger recv() - // through the baseclass. Since we're single-threaded this is - // probably overkill but it makes multi-threading easier if we - // choose to do that. - tickler_ = new ACE_Message_Block(1); -} - -/* Be sure we manage the lifetime of the tickler to prevent a memory - leak. -*/ -Recv::~Recv(void) -{ - tickler_->release(); -} - -/* By putting the tickler to ourselves we cause things to happen in - the baseclass that will invoke recv(). If we know we're single - threaded we could directly call recv() and be done with it but then - we'd have to do something else if we're multi-threaded. Just let - the baseclass worry about those things! -*/ -int Recv::get(void) -{ - return this->put( tickler_, 0 ); -} - -int Recv::recv(ACE_Message_Block * message, ACE_Time_Value *timeout) -{ - int rval; - - /* Xmit will send us the message length in clear-text. I - assume that will be less than 32-bytes! - */ - char msize[32]; - int b = 0; - - /* Read from the socket one byte at a time until we see then - end-of-string NULL character. Since the OS layers (at leas - in Unix) will provide some buffering this isn't as bad as - it may seem at first. - */ - do - { - rval = this->peer().recv( &msize[b], 1, timeout ); - if( rval == -1 ) - { - error_ = 1; - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Recv::recv() Failed to get message size."), -1); - } - } - while( msize[b++] != 0 ); - - int size = atoi(msize); - - // Make a block big enough to contain the data we'll read - message = new ACE_Message_Block( size ); - - // Read the actual message data into our new message block - rval = this->peer().recv_n( message->wr_ptr(), size, 0, timeout ); - - // If we got the data correctly then send it on upstream. - if( rval > 0 ) - { - message->wr_ptr( rval ); - return( this->put_next( message ) ); - } - - // Something bad happend on the recv_n(). Set an error flag - // and return error. - error_ = 1; - - return( -1 ); -} diff --git a/docs/tutorials/015/Recv.h b/docs/tutorials/015/Recv.h deleted file mode 100644 index a7058435bf5..00000000000 --- a/docs/tutorials/015/Recv.h +++ /dev/null @@ -1,62 +0,0 @@ - -// $Id$ - -#ifndef RECV_H -#define RECV_h - -#include "Protocol_Task.h" - -class ACE_SOCK_Stream; - -/* Get some data from the peer and send it upstream for - de-protocol-ization. -*/ -class Recv : public Protocol_Task -{ -public: - - typedef Protocol_Task inherited; - - // Give it someone to talk to... - Recv( ACE_SOCK_Stream & _peer ); - - ~Recv(void); - - // Trigger a read from the socket - int get(void); - - // In some cases it might be easier to check the "state" of the - // Recv object than to rely on return codes filtering back to - // you. - int error(void) - { - return this->error_; - } - -protected: - - ACE_SOCK_Stream & peer(void) - { - return this->peer_; - } - - // The baseclass will trigger this when our get() method is - // called. A message block of the appropriate size is created, - // filled and passed up the stream. - int recv(ACE_Message_Block * message, - ACE_Time_Value *timeout = 0); - -private: - // Our endpoint - ACE_SOCK_Stream & peer_; - - // get() uses a bogus message block to cause the baseclass to - // invoke recv(). To avoid memory thrashing, we create that - // bogus message once and reuse it for the life of Recv. - ACE_Message_Block * tickler_; - - // Our error flag (duh) - int error_; -}; - -#endif // RECV_H diff --git a/docs/tutorials/015/Server_i.cpp b/docs/tutorials/015/Server_i.cpp deleted file mode 100644 index dedbcd720f6..00000000000 --- a/docs/tutorials/015/Server_i.cpp +++ /dev/null @@ -1,71 +0,0 @@ - -// $Id$ - -#include "Server_i.h" - -/* We have to allocate space for our static finished_ flag. We also - initialize it to 'false' so that we don't exit immediately. -*/ -sig_atomic_t Server::finished_ = 0; - -/* The simple constructor and destructor don't do anything but give us - a place to expand in the future if we want. -*/ -Server::Server(void) -{ - ; -} - -Server::~Server(void) -{ - ; -} - -/* Opening the server is as simple as opening the acceptor with the - default ACE_Reactor instance. If we want to allow multiple - instances of Server objects then we should have an ACE_Reactor - member variable that we can register with. -*/ -int Server::open(void) -{ - if (acceptor_.open (ACE_INET_Addr (ACE_DEFAULT_SERVER_PORT), ACE_Reactor::instance()) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - - return(0); -} - -/* Running the server just means that we execute the basic event - loop for the reactor. Again, if we had a private reactor then we - could have multiple server's in their run() method. -*/ -int Server::run(void) -{ - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server daemon\n")); - - ACE_Time_Value timeout(2); - - // Here's the basic event loop. I have a 2-second timeout on - // the handle_events() so that we don't have to wait too long - // when we set the finished_ flag. - while (!finished_) - { - ACE_Reactor::instance()->handle_events (&timeout); - } - - // Close the acceptor when we're done. This may be handled by - // the framework but it's good practice to be explicit about things. - acceptor_.close(); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server daemon\n")); - - return 0; -} - -/* The close() method simply sets the finished_ flag so that run() - will leave the event loop and exit. -*/ -int Server::close(void) -{ - finished_ = 1; - return(0); -} diff --git a/docs/tutorials/015/Server_i.h b/docs/tutorials/015/Server_i.h deleted file mode 100644 index 6b1eecf05e5..00000000000 --- a/docs/tutorials/015/Server_i.h +++ /dev/null @@ -1,52 +0,0 @@ - -// $Id$ - -#ifndef SERVER_H -#define SERVER_H - -#include "ace/Acceptor.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "ace/SOCK_Acceptor.h" -#include "Handler.h" - -/* Anytime I have templates I try to remember to create a typedef for - the parameterized object. It makes for much less typing later! -*/ -typedef ACE_Acceptor < Handler, ACE_SOCK_ACCEPTOR > Acceptor; - -class Server -{ -public: - // Our simple constructor takes no parameters. To make the - // server a bit more useful, you may want to pass in the - // TCP/IP port to be used by the acceptor. - Server(void); - ~Server(void); - - // Open the server for business - int open(void); - - // Close all server instances by setting the finished_ flag. - // Actually, the way this class is written, you can only have - // one instance. - static int close(void); - - // Run the server's main loop. The use of the gloabl - // ACE_Reactor by this method is what limits us to one Server - // instance. - int run(void); - -private: - // This will accept client connection requests and instantiate - // a Handler object for each new connection. - Acceptor acceptor_; - - // Our shutdown flag - static sig_atomic_t finished_; -}; - -#endif // SERVER_H diff --git a/docs/tutorials/015/Xmit.cpp b/docs/tutorials/015/Xmit.cpp deleted file mode 100644 index fb80ab8aa34..00000000000 --- a/docs/tutorials/015/Xmit.cpp +++ /dev/null @@ -1,84 +0,0 @@ - -// $Id$ - -#include "Xmit.h" -#include "ace/SOCK_Stream.h" - -/* Construct the object with the peer connection and choose not to - activate ourselves into a dedicated thread. You might get some - performance gain by activating but if you really want a - multi-threaded apprroach you should handle that as a separate - issue. Attempting to force threading at this level will likely - cause more trouble than you want to deal with. -*/ -Xmit::Xmit( ACE_SOCK_Stream & _peer ) - : inherited(0), peer_(_peer) -{ -} - -Xmit::~Xmit(void) -{ -} - -/* Check to see if we're being closed by the stream (flags != 0) or if - we're responding to the exit of our svc() method. -*/ -int Xmit::close(u_long flags) -{ - // Take care of the baseclass closure. - int rval = inherited::close(flags); - - // Only if we're being called at the stream shutdown do we close - // the peer connection. If, for some reason, we were activated - // into one or more threads we wouldn't want to close the pipe - // before all threads had a chance to flush their data. - if( flags ) - { - peer().close(); - } - - return( rval ); -} - -/* Our overload of send() will take care of sending the data to the - peer. -*/ -int Xmit::send(ACE_Message_Block *message, ACE_Time_Value *timeout) -{ - int rval; - - ACE_DEBUG ((LM_INFO, "(%P|%t) Xmit::send() sending (%s)(%d)\n", message->rd_ptr(), message->length() )); - - /* Since we're going to be sending data that may have been - compressed and encrypted it's probably important for the - receiver to get an entire "block" instead of having a - partial read. - - For that reason, we'll send the length of the message block - (in clear-text) to the peer so that it can then recv_n() - the entire block contents in one read operation. - */ - char msize[32]; - sprintf(msize,"%d",message->length()); - - // Be sure we send the end-of-string NULL so that Recv will - // know when to stop assembling the length. - rval = this->peer().send_n( msize, strlen(msize)+1, 0, timeout ); - - if( rval == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Xmit::send() Failed to send message size."), -1); - } - - /* Now we send the actual data. If you're worried about - network efficiency then you may choose to create one buffer - containing msize and the message data and send it all at - once. - */ - rval = this->peer().send_n( message->rd_ptr(), message->length(), 0, timeout ); - - // Release the message block since we're done with it. - message->release(); - - return( rval ); -} diff --git a/docs/tutorials/015/Xmit.h b/docs/tutorials/015/Xmit.h deleted file mode 100644 index 097f3afdaba..00000000000 --- a/docs/tutorials/015/Xmit.h +++ /dev/null @@ -1,49 +0,0 @@ - -// $Id$ - -#ifndef XMIT_H -#define XMIT_h - -#include "Protocol_Task.h" - -// Forward reference reduces #include dependencies -class ACE_SOCK_Stream; - -/* A class suitable for sending data to a peer from within an - ACE_Stream. - */ -class Xmit : public Protocol_Task -{ -public: - - typedef Protocol_Task inherited; - - // We must be given a valid peer when constructed. Without that - // we don't know who to send data to. - Xmit( ACE_SOCK_Stream & _peer ); - - ~Xmit(void); - - // As you know, close() will be called in a couple of ways by the - // ACE framework. We use that opportunity to terminate the - // connection to the peer. - int close(u_long flags); - -protected: - - ACE_SOCK_Stream & peer(void) - { - return this->peer_; - } - - // Send the data to the peer. By now it will have been - // completely protocol-ized by other tasks in the stream. - int send(ACE_Message_Block *message, - ACE_Time_Value *timeout); - -private: - // A representation of the peer we're talking to. - ACE_SOCK_Stream & peer_; -}; - -#endif // XMIT_H diff --git a/docs/tutorials/015/client.cpp b/docs/tutorials/015/client.cpp deleted file mode 100644 index a573b4f3902..00000000000 --- a/docs/tutorials/015/client.cpp +++ /dev/null @@ -1,70 +0,0 @@ - -// $Id$ - -/* The Client object will implement the nasty details of connecting to - communicating with the server -*/ -#include "Client_i.h" - -int main(int argc, char *argv[]) -{ - // How many messages will we send? - int mcount = argc > 1 ? ACE_OS::atoi(argv[1]) : 3; - - // Construct a Client with our desired endpoint. - Client client(ACE_DEFAULT_SERVER_PORT,ACE_DEFAULT_SERVER_HOST); - - // Attempt to open the connection to the server. - if( client.open() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Client::open()"), -1); - } - - // Send a few messages to the server and get some responses... - for( int i = 0 ; i < mcount ; ++i ) - { - // Since we'll be using a Protocol Stream (even though we - // don't know that at this level) we require the use of - // ACE_Message_Block objects to send/receive data. - ACE_Message_Block * message = new ACE_Message_Block( 128 ); - - // Construct a silly message to send to the server. - // Notice that we're careful to add one to the strlen() so - // that we also send the end-of-string NULL character. - ACE_OS::sprintf (message->wr_ptr (), "This is message %d.", i); - message->wr_ptr (strlen (message->rd_ptr ())+1); - - // client will take ownership of the message block so that - // we don't have to remember to release(). We *do* have - // to remember not to use it after put() since it may be - // released almost immediately. - client.put( message ); - - ACE_Message_Block * response; - - // get() takes an ACE_Message_Block pointer reference. We then - // assume ownership of it and must release() when we're done. - if( client.get( response ) == -1 ) - { - ACE_DEBUG ((LM_INFO, "(%P|%t) Failed to get response from server\n" )); - break; - } - - ACE_DEBUG ((LM_INFO, "(%P|%t) The server's response: (%s)\n", - response->rd_ptr())); - - // Now that we're through with the response we have to - // release() it to avoid memory leaks. - response->release(); - } - - ACE_DEBUG ((LM_INFO, "(%P|%t) Shutting down the stream\n" )); - - // Before we exit, it's a good idea to properly close() the connection. - if( client.close() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "Client::close()"), -1); - } - - return(0); -} diff --git a/docs/tutorials/015/combine.shar b/docs/tutorials/015/combine.shar deleted file mode 100644 index 800c35231fd..00000000000 --- a/docs/tutorials/015/combine.shar +++ /dev/null @@ -1,1004 +0,0 @@ -#!/bin/sh -# This is a shell archive (produced by GNU sharutils 4.2). -# To extract the files from this archive, save it to some FILE, remove -# everything before the `!/bin/sh' line above, then type `sh FILE'. -# -# Made on 1998-10-22 19:58 EDT by <jcej@chiroptera.tragus.org>. -# Source directory was `/var/home/jcej/projects/ACE_wrappers/docs/tutorials/015'. -# -# Existing files will *not* be overwritten unless `-c' is specified. -# -# This shar contains: -# length mode name -# ------ ---------- ------------------------------------------ -# 414 -rw-rw-r-- hdr -# 419 -rw-rw-r-- bodies -# 1183 -rw-rw-r-- page01.pre -# 194 -rw-rw-r-- page02.pre -# 318 -rw-rw-r-- page03.pre -# 178 -rw-rw-r-- page04.pre -# 304 -rw-rw-r-- page05.pre -# 418 -rw-rw-r-- page06.pre -# 321 -rw-rw-r-- page07.pre -# 501 -rw-rw-r-- page08.pre -# 640 -rw-rw-r-- page09.pre -# 978 -rw-rw-r-- page10.pre -# 334 -rw-rw-r-- page11.pre -# 334 -rw-rw-r-- page12.pre -# 326 -rw-rw-r-- page13.pre -# 540 -rw-rw-r-- page14.pre -# 770 -rw-rw-r-- page15.pre -# 660 -rw-rw-r-- page16.pre -# 213 -rw-rw-r-- page17.pre -# 372 -rw-rw-r-- page18.pre -# 281 -rw-rw-r-- page19.pre -# 356 -rw-rw-r-- page20.pre -# 151 -rw-rw-r-- page21.pre -# 2567 -rw-rw-r-- page22.pre -# 406 -rw-rw-r-- page04.pst -# 617 -rw-rw-r-- page09.pst -# -save_IFS="${IFS}" -IFS="${IFS}:" -gettext_dir=FAILED -locale_dir=FAILED -first_param="$1" -for dir in $PATH -do - if test "$gettext_dir" = FAILED && test -f $dir/gettext \ - && ($dir/gettext --version >/dev/null 2>&1) - then - set `$dir/gettext --version 2>&1` - if test "$3" = GNU - then - gettext_dir=$dir - fi - fi - if test "$locale_dir" = FAILED && test -f $dir/shar \ - && ($dir/shar --print-text-domain-dir >/dev/null 2>&1) - then - locale_dir=`$dir/shar --print-text-domain-dir` - fi -done -IFS="$save_IFS" -if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED -then - echo=echo -else - TEXTDOMAINDIR=$locale_dir - export TEXTDOMAINDIR - TEXTDOMAIN=sharutils - export TEXTDOMAIN - echo="$gettext_dir/gettext -s" -fi -touch -am 1231235999 $$.touch >/dev/null 2>&1 -if test ! -f 1231235999 && test -f $$.touch; then - shar_touch=touch -else - shar_touch=: - echo - $echo 'WARNING: not restoring timestamps. Consider getting and' - $echo "installing GNU \`touch', distributed in GNU File Utilities..." - echo -fi -rm -f 1231235999 $$.touch -# -if mkdir _sh18487; then - $echo 'x -' 'creating lock directory' -else - $echo 'failed to create lock directory' - exit 1 -fi -# ============= hdr ============== -if test -f 'hdr' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'hdr' '(file already exists)' -else - $echo 'x -' extracting 'hdr' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'hdr' && -<HTML> -<HEAD> -X <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> -X <META NAME="Author" CONTENT="James CE Johnson"> -X <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> -X -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> -X -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> -X -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 1019163798 'hdr' && - chmod 0664 'hdr' || - $echo 'restore of' 'hdr' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'hdr:' 'MD5 check failed' -41322d388f7bb6c8eba031c4a6ab53ce hdr -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'hdr'`" - test 414 -eq "$shar_count" || - $echo 'hdr:' 'original size' '414,' 'current size' "$shar_count!" - fi -fi -# ============= bodies ============== -if test -f 'bodies' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'bodies' '(file already exists)' -else - $echo 'x -' extracting 'bodies' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'bodies' && -# -# The client application specific files -# -PAGE=2 -client.cpp -Client_i.h -Client_i.cpp -# -# The server application specific files -# -server.cpp -Server_i.h -Server_i.cpp -Handler.h -Handler.cpp -# -# The basic protocol stream -# -Protocol_Stream.h -Protocol_Stream.cpp -Protocol_Task.h -Protocol_Task.cpp -# -# Send/Receive objects -# -XXmit.h -XXmit.cpp -Recv.h -Recv.cpp -# -# Protocol objects -# -Compressor.h -Compressor.cpp -Crypt.h -Crypt.cpp -SHAR_EOF - $shar_touch -am 1022195498 'bodies' && - chmod 0664 'bodies' || - $echo 'restore of' 'bodies' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'bodies:' 'MD5 check failed' -a6c99d6567b0640ad524b196dc43647e bodies -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`" - test 419 -eq "$shar_count" || - $echo 'bodies:' 'original size' '419,' 'current size' "$shar_count!" - fi -fi -# ============= page01.pre ============== -if test -f 'page01.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page01.pre' '(file already exists)' -else - $echo 'x -' extracting 'page01.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page01.pre' && -X -In a typical client/server system you will be sending and receiving -X data. That's the whole point after all. -<P> -In the client/server tutorials that we've done so far it was just a -X matter of sending a buffer of data to the peer. This was done -X with the send*() and recv*() methods of the ACE_SOCK* objects. -<P> -In a more robust system, one might want to process the data before -X sending it to a peer and "unprocess" it after reading from a -X peer. These processing steps might include encryption, -X compression, applying checksums or any number of other actions. -<P> -In this tutorial a Protocol_Stream object is created to encrypt and -X compress* data being sent between peers. Both client and server -X applications are presented as well. I present the application -level code first and then go into the details of the protocol stream -and it's helper objects. If the stream stuff in the application logic -is confusing then just read on by and come back to it after the later -discussions. -X -<P> -<font size=-1>* Ok, I didn't really implement encryption and -X compression objects. I'll leave that as a thought -X exercise!</font> -SHAR_EOF - $shar_touch -am 1019163798 'page01.pre' && - chmod 0664 'page01.pre' || - $echo 'restore of' 'page01.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page01.pre:' 'MD5 check failed' -2a7a0fad3e88fcaa6b70cedbf873192f page01.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`" - test 1183 -eq "$shar_count" || - $echo 'page01.pre:' 'original size' '1183,' 'current size' "$shar_count!" - fi -fi -# ============= page02.pre ============== -if test -f 'page02.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page02.pre' '(file already exists)' -else - $echo 'x -' extracting 'page02.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page02.pre' && -We'll take a look first at the client application. As usual, our goal -X is to keep the main() application as simple as possible and -X delegate the tricky stuff to another object. -X -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page02.pre' && - chmod 0664 'page02.pre' || - $echo 'restore of' 'page02.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page02.pre:' 'MD5 check failed' -6a2e64962c95b349625f418502c95952 page02.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`" - test 194 -eq "$shar_count" || - $echo 'page02.pre:' 'original size' '194,' 'current size' "$shar_count!" - fi -fi -# ============= page03.pre ============== -if test -f 'page03.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page03.pre' '(file already exists)' -else - $echo 'x -' extracting 'page03.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page03.pre' && -The Client object is designed to hide all of the messy connection -X logic from it's users. It also provides put/get methods for -X sending data to the server and receiving the server's response. -X Note the Protocol_Stream member that will take care of -X converting and sending/receiving the data. -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page03.pre' && - chmod 0664 'page03.pre' || - $echo 'restore of' 'page03.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page03.pre:' 'MD5 check failed' -95326c064b10bbda428d3c967f285760 page03.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`" - test 318 -eq "$shar_count" || - $echo 'page03.pre:' 'original size' '318,' 'current size' "$shar_count!" - fi -fi -# ============= page04.pre ============== -if test -f 'page04.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page04.pre' '(file already exists)' -else - $echo 'x -' extracting 'page04.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page04.pre' && -The implementation of the Client object. Only the open() method -X really does any work. The other methods simply delegate their -X function to the Protocol_Stream. -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page04.pre' && - chmod 0664 'page04.pre' || - $echo 'restore of' 'page04.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page04.pre:' 'MD5 check failed' -2955ca8d3b0fc6840f3d371aea528b8d page04.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`" - test 178 -eq "$shar_count" || - $echo 'page04.pre:' 'original size' '178,' 'current size' "$shar_count!" - fi -fi -# ============= page05.pre ============== -if test -f 'page05.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page05.pre' '(file already exists)' -else - $echo 'x -' extracting 'page05.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page05.pre' && -Like the client, we want to keep the main() part of our server code as -X simple as possible. This is done by putting most of the work -X into the Handler object that will deal with client connections. -XFrom the looks of the code below, I think we've been successful in our -simplification. -<HR> -X -SHAR_EOF - $shar_touch -am 1019163798 'page05.pre' && - chmod 0664 'page05.pre' || - $echo 'restore of' 'page05.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page05.pre:' 'MD5 check failed' -8833b0d7f90a4d13f68b8cdb9147c29a page05.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`" - test 304 -eq "$shar_count" || - $echo 'page05.pre:' 'original size' '304,' 'current size' "$shar_count!" - fi -fi -# ============= page06.pre ============== -if test -f 'page06.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page06.pre' '(file already exists)' -else - $echo 'x -' extracting 'page06.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page06.pre' && -The Server object exists in order simplify the -main() application level. To that end, it hides the details of -creating an acceptor and managing the reactor. -<P> -The static close() method available for a signal handler as you saw on -the previous page. Of course the assumption here is that there would -only be one Server instance but since you can't provide a TCP/IP port, -that's probably a valid assumption! -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page06.pre' && - chmod 0664 'page06.pre' || - $echo 'restore of' 'page06.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page06.pre:' 'MD5 check failed' -06a0abefdf4e704b42147f433bd27e4d page06.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page06.pre'`" - test 418 -eq "$shar_count" || - $echo 'page06.pre:' 'original size' '418,' 'current size' "$shar_count!" - fi -fi -# ============= page07.pre ============== -if test -f 'page07.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page07.pre' '(file already exists)' -else - $echo 'x -' extracting 'page07.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page07.pre' && -And now the implementation of Server. This is actually just the -main() code from a previous tutorial broken into appropriate method -calls. It may seem silly to do this rather than keeping the stuff in -main() but you'll find that you have less trouble enhancing an -application when you take this sort of approach. -<HR> -X -SHAR_EOF - $shar_touch -am 1019163798 'page07.pre' && - chmod 0664 'page07.pre' || - $echo 'restore of' 'page07.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page07.pre:' 'MD5 check failed' -7dfb75884939c3c05ee1e1000956e9f4 page07.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page07.pre'`" - test 321 -eq "$shar_count" || - $echo 'page07.pre:' 'original size' '321,' 'current size' "$shar_count!" - fi -fi -# ============= page08.pre ============== -if test -f 'page08.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page08.pre' '(file already exists)' -else - $echo 'x -' extracting 'page08.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page08.pre' && -The Handler object is our event handler. You can use either -ACE_Event_Handler or ACE_Svc_Handler<> for the baseclass. I generally -prefer the latter since it takes care of some housekeeping that I -would otherwise be responsible for. -<P> -The class declaration is taken almost exactly from a previous -tutorial. A good design will have a simple handler object that will -collect data from the peer and pass it along to another object for -processing. Again, keep it simple and delegate authority. -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page08.pre' && - chmod 0664 'page08.pre' || - $echo 'restore of' 'page08.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page08.pre:' 'MD5 check failed' -471889eb736a025fc46719549bca160a page08.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page08.pre'`" - test 501 -eq "$shar_count" || - $echo 'page08.pre:' 'original size' '501,' 'current size' "$shar_count!" - fi -fi -# ============= page09.pre ============== -if test -f 'page09.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page09.pre' '(file already exists)' -else - $echo 'x -' extracting 'page09.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page09.pre' && -Like any other event handler, the handle_input() method will be -responsible for getting data from the peer() and doing something with -it. In this case, we have a Protocol_Stream to deal with. We'll use -the stream for the actual I/O but we are ultimately responsible for -processing the data from the peer. To do that, we've created a -Handler_Task that fits within the Protocol_Stream framework to process -data that has been received. Handler::handle_input() will tell the stream that -it's time to read data and that data will eventually show up at -Handler_Task::recv() where we'll process it as required by our -application logic. -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page09.pre' && - chmod 0664 'page09.pre' || - $echo 'restore of' 'page09.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page09.pre:' 'MD5 check failed' -da5c4b11d356dc9caf3a8e3b6b2527a6 page09.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page09.pre'`" - test 640 -eq "$shar_count" || - $echo 'page09.pre:' 'original size' '640,' 'current size' "$shar_count!" - fi -fi -# ============= page10.pre ============== -if test -f 'page10.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page10.pre' '(file already exists)' -else - $echo 'x -' extracting 'page10.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page10.pre' && -And so finally we come to the Protocol_Stream. That, after all, is -the focus of the entire tutorial but it took us half of the day to get -here! -<P> -The Protocol_Stream uses an ACE_Stream to move an ACE_Message_Block -through a series of tasks. Each task in the stream is responsible for -performing some operation on the data in the message block. That is -the nature of a protocol stream (or "stack" if you prefer). In this -stream, the data is compressed and encrypted* on its way between -peers. We also allow users of the stream to install a reader task to -handle data that percolates up from the peer. As you saw a page or -two ago, this is most useful for a server. -X -<P> -<font size=-1>*Again, I just pretend to do these things. It would -take another day or two to go through any sort of reasonable -encryption or compression!</font> -<P> -Before we get into the code, here's a picture that's shows what's -going on here. -<P><center><img src="stream.gif"></center></p> -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page10.pre' && - chmod 0664 'page10.pre' || - $echo 'restore of' 'page10.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page10.pre:' 'MD5 check failed' -a74423390fb5217104c6d89d7f202e8b page10.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page10.pre'`" - test 978 -eq "$shar_count" || - $echo 'page10.pre:' 'original size' '978,' 'current size' "$shar_count!" - fi -fi -# ============= page11.pre ============== -if test -f 'page11.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page11.pre' '(file already exists)' -else - $echo 'x -' extracting 'page11.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page11.pre' && -And now the implementation of the Protocol_Stream. There are more -lines of code here than we've seen so far but it still isn't -complicated. The basic idea is to construct the ACE_Stream with our -set of protocol objects that will manipulate the data. Our primary -concern in this file is to get everything in the correct order! -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page11.pre' && - chmod 0664 'page11.pre' || - $echo 'restore of' 'page11.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page11.pre:' 'MD5 check failed' -b0e968102fb417b12710e99465f4e387 page11.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page11.pre'`" - test 334 -eq "$shar_count" || - $echo 'page11.pre:' 'original size' '334,' 'current size' "$shar_count!" - fi -fi -# ============= page12.pre ============== -if test -f 'page12.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page12.pre' '(file already exists)' -else - $echo 'x -' extracting 'page12.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page12.pre' && -And now the implementation of the Protocol_Stream. There are more -lines of code here than we've seen so far but it still isn't -complicated. The basic idea is to construct the ACE_Stream with our -set of protocol objects that will manipulate the data. Our primary -concern in this file is to get everything in the correct order! -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page12.pre' && - chmod 0664 'page12.pre' || - $echo 'restore of' 'page12.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page12.pre:' 'MD5 check failed' -b0e968102fb417b12710e99465f4e387 page12.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page12.pre'`" - test 334 -eq "$shar_count" || - $echo 'page12.pre:' 'original size' '334,' 'current size' "$shar_count!" - fi -fi -# ============= page13.pre ============== -if test -f 'page13.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page13.pre' '(file already exists)' -else - $echo 'x -' extracting 'page13.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page13.pre' && -The Protocol_Task implementation takes care of the open(), close(), -put() and svc() methods so that derivatives can concentrate on the -send() and recv() methods. After a while you find that most -ACE_Task<> derivatives look very similar in the four basic methods and -only need one or two additional to do any real work. -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page13.pre' && - chmod 0664 'page13.pre' || - $echo 'restore of' 'page13.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page13.pre:' 'MD5 check failed' -8b74a6d79d158222928097a9bb1335db page13.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page13.pre'`" - test 326 -eq "$shar_count" || - $echo 'page13.pre:' 'original size' '326,' 'current size' "$shar_count!" - fi -fi -# ============= page14.pre ============== -if test -f 'page14.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page14.pre' '(file already exists)' -else - $echo 'x -' extracting 'page14.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page14.pre' && -The Xmit object knows how to send data to the peer. It sits at the -tail of the stream and gets everything that flows down from the head. -In keeping with the spirit of things, this object does only one thing -and doesn't concern itself with anyone else' details. -<P> -The only thing you might want to do is combine it with Recv. Why? -As you'll realize in a page or two, the Xmit and Recv objects must -interact if you're going to ensure a safe transit. By having a single -object it's easier to coordinate and maintain the interaction. -<HR> -SHAR_EOF - $shar_touch -am 1019203498 'page14.pre' && - chmod 0664 'page14.pre' || - $echo 'restore of' 'page14.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page14.pre:' 'MD5 check failed' -bfc300ca2da5b82a5e452713cbf2f544 page14.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page14.pre'`" - test 540 -eq "$shar_count" || - $echo 'page14.pre:' 'original size' '540,' 'current size' "$shar_count!" - fi -fi -# ============= page15.pre ============== -if test -f 'page15.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page15.pre' '(file already exists)' -else - $echo 'x -' extracting 'page15.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page15.pre' && -The implementation of Xmit isn't too complicated. If we choose to -combine it with the Recv task we simply lift the recv() method from -that object and drop it into this one. -<P> -Note that close() must decide if it's being called when the stream is -shutdown or when it's svc() method exits. Since we tell the baseclass -not to use any threads it's a safe bet that flags will always be -non-zero. Still, it's good practice to plan for the future by -checking the value. -<P> -Note also that when we send the data we prefix it with the data size. -This let's our sibling Recv ensure that an entire block is received -together. This can be very important for compression and encryption -processes which typically work better with blocks of data instead of -streams of data. -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page15.pre' && - chmod 0664 'page15.pre' || - $echo 'restore of' 'page15.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page15.pre:' 'MD5 check failed' -0d79137eaedd73b820037fcafe6e16b6 page15.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page15.pre'`" - test 770 -eq "$shar_count" || - $echo 'page15.pre:' 'original size' '770,' 'current size' "$shar_count!" - fi -fi -# ============= page16.pre ============== -if test -f 'page16.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page16.pre' '(file already exists)' -else - $echo 'x -' extracting 'page16.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page16.pre' && -Recv is the sibling to Xmit. Again, they could be combined into a -single object if you want. -<P> -An ACE_Stream is designed to handle downstream traffic very -well. You put() data into it and it flows along towards the tail. -However, there doesn't seem to be a way to put data in such that it -will travel upstream. To get around that, I've added a get() method -to Recv that will trigger a read on the socket. Recv will then put -the data to the next upstream module and we're on our way. As noted -earlier, that data will eventually show up either in the <i>reader</i> -(if installed on the stream open()) or the stream head reader task's -message queue. -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page16.pre' && - chmod 0664 'page16.pre' || - $echo 'restore of' 'page16.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page16.pre:' 'MD5 check failed' -2d89b3c894cfcfdfef47ae506913cdad page16.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page16.pre'`" - test 660 -eq "$shar_count" || - $echo 'page16.pre:' 'original size' '660,' 'current size' "$shar_count!" - fi -fi -# ============= page17.pre ============== -if test -f 'page17.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page17.pre' '(file already exists)' -else - $echo 'x -' extracting 'page17.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page17.pre' && -The Recv implementation is nearly as simple as Xmit. There's -opportunity for error when we get the message size and we have to -manage the lifetime of the tickler but other than that it's pretty -basic stuff. -<HR> -SHAR_EOF - $shar_touch -am 1019163798 'page17.pre' && - chmod 0664 'page17.pre' || - $echo 'restore of' 'page17.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page17.pre:' 'MD5 check failed' -7db337f2c6ec74d75560534dec550b0e page17.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page17.pre'`" - test 213 -eq "$shar_count" || - $echo 'page17.pre:' 'original size' '213,' 'current size' "$shar_count!" - fi -fi -# ============= page18.pre ============== -if test -f 'page18.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page18.pre' '(file already exists)' -else - $echo 'x -' extracting 'page18.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page18.pre' && -This and the next three pages present the protocol objects that -provide compression and encryption. If you were hoping to learn the -secrets of compression and encryption then I'm going to disappoint -you. There are some really good libraries out there that do this -stuff though and if anyone wants to integrate one of them into the -tutorial I'll be glad to take it! -<HR> -SHAR_EOF - $shar_touch -am 1019203698 'page18.pre' && - chmod 0664 'page18.pre' || - $echo 'restore of' 'page18.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page18.pre:' 'MD5 check failed' -dc5f706bd5a27009aed167c0b137648e page18.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page18.pre'`" - test 372 -eq "$shar_count" || - $echo 'page18.pre:' 'original size' '372,' 'current size' "$shar_count!" - fi -fi -# ============= page19.pre ============== -if test -f 'page19.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page19.pre' '(file already exists)' -else - $echo 'x -' extracting 'page19.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page19.pre' && -Here we implement the details of our compression. By having both -compression and decompression in one object it's easier to keep track -of implementation details. Splitting Xmit/Recv like I did will make -things more difficult if something has to change in their interaction. -<HR> -SHAR_EOF - $shar_touch -am 1019195798 'page19.pre' && - chmod 0664 'page19.pre' || - $echo 'restore of' 'page19.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page19.pre:' 'MD5 check failed' -4eb5dcd181f180d6c460971903efb288 page19.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page19.pre'`" - test 281 -eq "$shar_count" || - $echo 'page19.pre:' 'original size' '281,' 'current size' "$shar_count!" - fi -fi -# ============= page20.pre ============== -if test -f 'page20.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page20.pre' '(file already exists)' -else - $echo 'x -' extracting 'page20.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page20.pre' && -While I might be able to come up with a competitive compressor, I -don't have a snowball's chance to code up encryption. I'd be better -off piping the data through the standard Unix crypt command. -<P> -So, while I was lazy with Compress, I'm realistic with Crypt. I'll -show you the hooks and entry points and let someone else contribute an -encryptor. -<HR> -SHAR_EOF - $shar_touch -am 1019203798 'page20.pre' && - chmod 0664 'page20.pre' || - $echo 'restore of' 'page20.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page20.pre:' 'MD5 check failed' -7f75130d385a34b2c421a8d7cae69cc3 page20.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page20.pre'`" - test 356 -eq "$shar_count" || - $echo 'page20.pre:' 'original size' '356,' 'current size' "$shar_count!" - fi -fi -# ============= page21.pre ============== -if test -f 'page21.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page21.pre' '(file already exists)' -else - $echo 'x -' extracting 'page21.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page21.pre' && -The encryption implementation isn't any smarter than that of the -compressor. Still, the hooks are there for you to insert your -favorite library. -<HR> -SHAR_EOF - $shar_touch -am 1019203898 'page21.pre' && - chmod 0664 'page21.pre' || - $echo 'restore of' 'page21.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page21.pre:' 'MD5 check failed' -7f0f64452098cdef38c5496340a4b6c7 page21.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page21.pre'`" - test 151 -eq "$shar_count" || - $echo 'page21.pre:' 'original size' '151,' 'current size' "$shar_count!" - fi -fi -# ============= page22.pre ============== -if test -f 'page22.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page22.pre' '(file already exists)' -else - $echo 'x -' extracting 'page22.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page22.pre' && -Well, this has certainly been one of the more verbose tutorials to -date. I must say "thanks" to everyone who stuck it out this far! -<P> -A quick review of what we've done: -<UL> -X -<LI>Create a simple client application and Client object that uses a -Protocol Stream without really knowing how they work. The app (and -object) rely on the public interface of the Protocol Stream to get the -job done. At this level the protocol details are irrelevant. -<P> -<LI>Next, we create a simple server application and Server object -similar to the client. The Protocol Stream is of course used and we -have to know a little more so that we can insert a <i>reader</i> that -will ultimately process the data from the client. -<P> -<LI>We then go into the details of the Protocol_Stream implementation -and it's Protocol_Task object that forms the basis for the stream -tasks. Each object is kept as small and simple as possible to improve -reusability and future maintenance. -<P> -<LI>Finally, the individual protocol objects are discused. Separate -objects for the peer interface were created as well as the bogus -compressor and encryptor. The protocol can be extended or modified by -creating new such objects and installing them in the Protocol_Stream's -open() method. -X -</UL> -<P> -X -It doesn't sound like much but it certainly took a bunch of files to -get there. It's easy to get lost in the details when there's so much -to cover so you're encouraged to go over things a couple of times. -As always, enhancments of the tutorials is welcome! -<P> -Here's the complete file list: -<UL> -<LI><A HREF="client">Makefile</A> -<P> -<LI><A HREF="Makefile.client">client Makefile</A> -<LI><A HREF="client.cpp">client.cpp</A> -<LI><A HREF="Client_i.h">Client_i.h</A> -<LI><A HREF="Client_i.cpp">Client_i.cpp</A> -<P> -<LI><A HREF="Makefile.server">Server Makefile</A> -<LI><A HREF="server.cpp">server.cpp</A> -<LI><A HREF="Server_i.h">Server_i.h</A> -<LI><A HREF="Server_i.cpp">Server_i.cpp</A> -<LI><A HREF="Handler.h">Handler.h</A> -<LI><A HREF="Handler.cpp">Handler.cpp</A> -<P> -<LI><A HREF="Protocol_Stream.cpp">Protocol_Stream.cpp</A> -<LI><A HREF="Protocol_Stream.h">Protocol_Stream.h</A> -<LI><A HREF="Protocol_Task.cpp">Protocol_Task.cpp</A> -<LI><A HREF="Protocol_Task.h">Protocol_Task.h</A> -<P> -<LI><A HREF="Xmit.cpp">Xmit.cpp</A> -<LI><A HREF="Xmit.h">Xmit.h</A> -<LI><A HREF="Recv.cpp">Recv.cpp</A> -<LI><A HREF="Recv.h">Recv.h</A> -<P> -<LI><A HREF="Compressor.cpp">Compressor.cpp</A> -<LI><A HREF="Compressor.h">Compressor.h</A> -<LI><A HREF="Crypt.cpp">Crypt.cpp</A> -<LI><A HREF="Crypt.h">Crypt.h</A> -</UL> -SHAR_EOF - $shar_touch -am 1022195898 'page22.pre' && - chmod 0664 'page22.pre' || - $echo 'restore of' 'page22.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page22.pre:' 'MD5 check failed' -9eae1b08c2e061a68bfc1f3cbc2f59de page22.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page22.pre'`" - test 2567 -eq "$shar_count" || - $echo 'page22.pre:' 'original size' '2567,' 'current size' "$shar_count!" - fi -fi -# ============= page04.pst ============== -if test -f 'page04.pst' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page04.pst' '(file already exists)' -else - $echo 'x -' extracting 'page04.pst' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page04.pst' && -<HR> -<P> -Ok, that's it for the client. We've seen a very simple main() -X followed by an equally simple Client object. -<P> -For a quick look back: -<UL> -<LI><A HREF="Makefile.client">client Makefile</A> -<LI><A HREF="client.cpp">client.cpp</A> -<LI><A HREF="Client_i.h">Client_i.h</A> -<LI><A HREF="Client_i.cpp">Client_i.cpp</A> -</UL> -<P> -Now we'll move on and examine the server counter-part of our client. -SHAR_EOF - $shar_touch -am 1022195698 'page04.pst' && - chmod 0664 'page04.pst' || - $echo 'restore of' 'page04.pst' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page04.pst:' 'MD5 check failed' -00419a8ab9a3ddae3261840b62afdc4a page04.pst -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pst'`" - test 406 -eq "$shar_count" || - $echo 'page04.pst:' 'original size' '406,' 'current size' "$shar_count!" - fi -fi -# ============= page09.pst ============== -if test -f 'page09.pst' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page09.pst' '(file already exists)' -else - $echo 'x -' extracting 'page09.pst' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page09.pst' && -<HR> -<P> -That's it for the server-specific code. I think I've been fairly -successful in keeping it simple and to the point. There are a couple -of places where the as-yet-undescribed Protocol_Stream pops up and may -cause confusion. We're going to discuss that mystery now but before -we do here's the list of server files if you want to review: -X -<UL> -<LI><A HREF="Makefile.server">Server Makefile</A> -<LI><A HREF="server.cpp">server.cpp</A> -<LI><A HREF="Server_i.h">Server_i.h</A> -<LI><A HREF="Server_i.cpp">Server_i.cpp</A> -<LI><A HREF="Handler.h">Handler.h</A> -<LI><A HREF="Handler.cpp">Handler.cpp</A> -</UL> -<P> -SHAR_EOF - $shar_touch -am 1022195698 'page09.pst' && - chmod 0664 'page09.pst' || - $echo 'restore of' 'page09.pst' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page09.pst:' 'MD5 check failed' -a96009f43a6fe8e6b52ffa923993a3e1 page09.pst -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page09.pst'`" - test 617 -eq "$shar_count" || - $echo 'page09.pst:' 'original size' '617,' 'current size' "$shar_count!" - fi -fi -rm -fr _sh18487 -exit 0 diff --git a/docs/tutorials/015/page01.html b/docs/tutorials/015/page01.html deleted file mode 100644 index 9f12daac318..00000000000 --- a/docs/tutorials/015/page01.html +++ /dev/null @@ -1,41 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> - -In a typical client/server system you will be sending and receiving - data. That's the whole point after all. -<P> -In the client/server tutorials that we've done so far it was just a - matter of sending a buffer of data to the peer. This was done - with the send*() and recv*() methods of the ACE_SOCK* objects. -<P> -In a more robust system, one might want to process the data before - sending it to a peer and "unprocess" it after reading from a - peer. These processing steps might include encryption, - compression, applying checksums or any number of other actions. -<P> -In this tutorial a Protocol_Stream object is created to encrypt and - compress* data being sent between peers. Both client and server - applications are presented as well. I present the application -level code first and then go into the details of the protocol stream -and it's helper objects. If the stream stuff in the application logic -is confusing then just read on by and come back to it after the later -discussions. - -<P> -<font size=-1>* Ok, I didn't really implement encryption and - compression objects. I'll leave that as a thought - exercise!</font> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page02.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page02.html b/docs/tutorials/015/page02.html deleted file mode 100644 index ebe7c96186b..00000000000 --- a/docs/tutorials/015/page02.html +++ /dev/null @@ -1,93 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -We'll take a look first at the client application. As usual, our goal - is to keep the main() application as simple as possible and - delegate the tricky stuff to another object. - -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=red>/* The Client object will implement the nasty details of connecting to - communicating with the server -*/</font> -<font color=blue>#include</font> "<font color=green>Client_i.h</font>" - -int main(int argc, char *argv[]) -{ - <font color=red>// How many messages will we send?</font> - int mcount = argc > 1 ? <font color=#008888>ACE_OS::atoi</font>(argv[1]) : 3; - - <font color=red>// Construct a Client with our desired endpoint.</font> - Client client(ACE_DEFAULT_SERVER_PORT,ACE_DEFAULT_SERVER_HOST); - - <font color=red>// Attempt to open the connection to the server.</font> - if( client.open() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Client::open</font>()</font>"), -1); - } - - <font color=red>// Send a few messages to the server and get some responses...</font> - for( int i = 0 ; i < mcount ; ++i ) - { - <font color=red>// Since we'll be using a Protocol Stream (even though we</font> - <font color=red>// don't know that at this level) we require the use of</font> - <font color=red>// ACE_Message_Block objects to send/receive data.</font> - ACE_Message_Block * message = new ACE_Message_Block( 128 ); - - <font color=red>// Construct a silly message to send to the server.</font> - <font color=red>// Notice that we're careful to add one to the strlen() so </font> - <font color=red>// that we also send the end-of-string NULL character.</font> - <font color=#008888>ACE_OS::sprintf</font> (message->wr_ptr (), "<font color=green>This is message %d.</font>", i); - message->wr_ptr (strlen (message->rd_ptr ())+1); - - <font color=red>// client will take ownership of the message block so that </font> - <font color=red>// we don't have to remember to release(). We *do* have</font> - <font color=red>// to remember not to use it after put() since it may be</font> - <font color=red>// released almost immediately.</font> - client.put( message ); - - ACE_Message_Block * response; - - <font color=red>// get() takes an ACE_Message_Block pointer reference. We then</font> - <font color=red>// assume ownership of it and must release() when we're done.</font> - if( client.get( response ) == -1 ) - { - ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) Failed to get response from server\n</font>" )); - break; - } - - ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) The server's response: (%s)\n</font>", - response->rd_ptr())); - - <font color=red>// Now that we're through with the response we have to</font> - <font color=red>// release() it to avoid memory leaks.</font> - response->release(); - } - - ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) Shutting down the stream\n</font>" )); - - <font color=red>// Before we exit, it's a good idea to properly close() the connection.</font> - if( client.close() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Client::close</font>()</font>"), -1); - } - - return(0); -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page03.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page03.html b/docs/tutorials/015/page03.html deleted file mode 100644 index 77358459764..00000000000 --- a/docs/tutorials/015/page03.html +++ /dev/null @@ -1,98 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -The Client object is designed to hide all of the messy connection - logic from it's users. It also provides put/get methods for - sending data to the server and receiving the server's response. - Note the Protocol_Stream member that will take care of - converting and sending/receiving the data. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#ifndef</font> <font color=purple>CLIENT_H</font> -<font color=blue>#define</font> <font color=purple>CLIENT_H</font> - -<font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>" - -<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>) -# pragma once -<font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font> - -<font color=blue>#include</font> "<font color=green>Protocol_Stream.h</font>" - -class ACE_Message_Block; - -<font color=red>/* Hide the details of connection and protocol-conformance from the - application-level logic. -*/</font> -class Client -{ -public: - <font color=red>// Provide the server information when constructing the</font> - <font color=red>// object. This could (and probably should) be moved to the</font> - <font color=red>// open() method.</font> - Client( u_short _port, const char * _server ); - - <font color=red>// Cleanup...</font> - ~Client(void); - - <font color=red>// Open the connection to the server.</font> - int open(void); - - <font color=red>// Close the connection to the server. Be sure to do this</font> - <font color=red>// before you let the Client go out of scope.</font> - int close(void); - - <font color=red>// Put a message to the server. The Client assumes ownership</font> - <font color=red>// of _message at that point and will release() it when done.</font> - <font color=red>// Do not use _message after passing it to put().</font> - int put( ACE_Message_Block * _message ); - - <font color=red>// Get a response from the server. The caller becomes the</font> - <font color=red>// owner of _response after this call and is responsible for</font> - <font color=red>// invoking release() when done.</font> - int get( ACE_Message_Block * & _response ); - -private: - <font color=red>// Protocol_Stream hides the protocol conformance details from</font> - <font color=red>// us.</font> - Protocol_Stream stream_; - - <font color=red>// We create a connection on the peer_ and then pass ownership</font> - <font color=red>// of it to the protocol stream.</font> - ACE_SOCK_Stream peer_; - - <font color=red>// Endpoing information saved by the constructor for use by open().</font> - u_short port_; - const char * server_; - - <font color=red>// Accessors for the complex member variables.</font> - - Protocol_Stream & stream(void) - { - return this->stream_; - } - - ACE_SOCK_Stream & peer(void) - { - return this->peer_; - } -}; - -<font color=blue>#endif</font> <font color=red>// CLIENT_H</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page04.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page04.html b/docs/tutorials/015/page04.html deleted file mode 100644 index 6ce78807797..00000000000 --- a/docs/tutorials/015/page04.html +++ /dev/null @@ -1,96 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -The implementation of the Client object. Only the open() method - really does any work. The other methods simply delegate their - function to the Protocol_Stream. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#include</font> "<font color=green>Client_i.h</font>" -<font color=blue>#include</font> "<font color=green>ace/Message_Block.h</font>" -<font color=blue>#include</font> "<font color=green>ace/INET_Addr.h</font>" -<font color=blue>#include</font> "<font color=green>ace/SOCK_Connector.h</font>" - -<font color=red>// Simple constructor just remembers the endpoint information for use by open.</font> -<font color=#008888>Client::Client</font>( u_short _port, const char * _server) - : port_(_port), server_(_server) -{ - ; -} - -<font color=red>/* Do nothing. This should probably call close() if we can make sure - that it's OK to close() multiple times. -*/</font> -<font color=#008888>Client::~Client</font>(void) -{ - ; -} - -<font color=red>/* Open the connection to the server. This is traditional ACE. We - simply construct an endpoint and use a connector to establish the - link. -*/</font> -int <font color=#008888>Client::open</font>( void ) -{ - ACE_INET_Addr addr(port_,server_); - ACE_SOCK_Connector con; - - if( con.connect(peer(),addr) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>ACE_SOCK_Connector::connect</font>()</font>"), -1); - } - - <font color=red>// Something new here... We have to use the protocol stream</font> - <font color=red>// to ensure that our data is in the correct format when</font> - <font color=red>// received by the server. Thus, we open the stream and</font> - <font color=red>// transfer ownership of the peer.</font> - return stream().open( peer() ); -} - -<font color=red>// The remainder of the functions just delegate to the stream.</font> - -int <font color=#008888>Client::close</font>( void ) -{ - return stream().close(); -} - -int <font color=#008888>Client::put</font>( ACE_Message_Block * _message ) -{ - return stream().put(_message,0); -} - -int <font color=#008888>Client::get</font>( ACE_Message_Block * & _response ) -{ - return stream().get(_response); -} -</PRE> -<HR> -<P> -Ok, that's it for the client. We've seen a very simple main() - followed by an equally simple Client object. -<P> -For a quick look back: -<UL> -<LI><A HREF="Makefile.client">client Makefile</A> -<LI><A HREF="client.cpp">client.cpp</A> -<LI><A HREF="Client_i.h">Client_i.h</A> -<LI><A HREF="Client_i.cpp">Client_i.cpp</A> -</UL> -<P> -Now we'll move on and examine the server counter-part of our client. -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page05.html b/docs/tutorials/015/page05.html deleted file mode 100644 index 82370135201..00000000000 --- a/docs/tutorials/015/page05.html +++ /dev/null @@ -1,71 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -Like the client, we want to keep the main() part of our server code as - simple as possible. This is done by putting most of the work - into the Handler object that will deal with client connections. -From the looks of the code below, I think we've been successful in our -simplification. -<HR> - -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#include</font> "<font color=green>Server_i.h</font>" - -<font color=red>// A signal handler that will close the server object</font> -extern "<font color=green>C</font>" void handler (int) -{ - <font color=#008888>Server::close</font>(); -} - -int main (int, char **) -{ - <font color=red>// The server object that abstracts away all of difficult parts.</font> - Server server; - - <font color=red>// Attempt to open the server. Like all good ACE-based</font> - <font color=red>// objects, we'll get -1 on failure.</font> - if( server.open() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>server.open()</font>"), -1); - } - - <font color=red>// Install a signal handler for ^C so that we can exit gracefully</font> - ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - <font color=red>// Run the server's main loop until we're interrupted</font> - if( server.run() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>server.run()</font>"), -1); - } - - return 0; -} - -<font color=red>/* These explicit instantiations were taken from an earlier tutorial. - Your compiler may require others as well. -*/</font> -<font color=blue>#if defined</font> (<font color=purple>ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION</font>) -template class ACE_Acceptor <Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -<font color=blue>#elif defined</font> (<font color=purple>ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA</font>) -<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Acceptor <Handler, ACE_SOCK_ACCEPTOR> -<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -<font color=blue>#endif</font> <font color=red>/* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */</font> - -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page06.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page06.html b/docs/tutorials/015/page06.html deleted file mode 100644 index 8a7663b4e92..00000000000 --- a/docs/tutorials/015/page06.html +++ /dev/null @@ -1,79 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -The Server object exists in order simplify the -main() application level. To that end, it hides the details of -creating an acceptor and managing the reactor. -<P> -The static close() method available for a signal handler as you saw on -the previous page. Of course the assumption here is that there would -only be one Server instance but since you can't provide a TCP/IP port, -that's probably a valid assumption! -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#ifndef</font> <font color=purple>SERVER_H</font> -<font color=blue>#define</font> <font color=purple>SERVER_H</font> - -<font color=blue>#include</font> "<font color=green>ace/Acceptor.h</font>" - -<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>) -# pragma once -<font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font> - -<font color=blue>#include</font> "<font color=green>ace/SOCK_Acceptor.h</font>" -<font color=blue>#include</font> "<font color=green>Handler.h</font>" - -<font color=red>/* Anytime I have templates I try to remember to create a typedef for - the parameterized object. It makes for much less typing later! -*/</font> -typedef ACE_Acceptor < Handler, ACE_SOCK_ACCEPTOR > Acceptor; - -class Server -{ -public: - <font color=red>// Our simple constructor takes no parameters. To make the</font> - <font color=red>// server a bit more useful, you may want to pass in the</font> - <font color=red>// TCP/IP port to be used by the acceptor.</font> - Server(void); - ~Server(void); - - <font color=red>// Open the server for business</font> - int open(void); - - <font color=red>// Close all server instances by setting the finished_ flag.</font> - <font color=red>// Actually, the way this class is written, you can only have</font> - <font color=red>// one instance.</font> - static int close(void); - - <font color=red>// Run the server's main loop. The use of the gloabl</font> - <font color=red>// ACE_Reactor by this method is what limits us to one Server</font> - <font color=red>// instance.</font> - int run(void); - -private: - <font color=red>// This will accept client connection requests and instantiate</font> - <font color=red>// a Handler object for each new connection.</font> - Acceptor acceptor_; - - <font color=red>// Our shutdown flag</font> - static sig_atomic_t finished_; -}; - -<font color=blue>#endif</font> <font color=red>// SERVER_H</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page07.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page07.html b/docs/tutorials/015/page07.html deleted file mode 100644 index 2e0e49f93fe..00000000000 --- a/docs/tutorials/015/page07.html +++ /dev/null @@ -1,96 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -And now the implementation of Server. This is actually just the -main() code from a previous tutorial broken into appropriate method -calls. It may seem silly to do this rather than keeping the stuff in -main() but you'll find that you have less trouble enhancing an -application when you take this sort of approach. -<HR> - -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#include</font> "<font color=green>Server_i.h</font>" - -<font color=red>/* We have to allocate space for our static finished_ flag. We also - initialize it to 'false' so that we don't exit immediately. -*/</font> -sig_atomic_t <font color=#008888>Server::finished_</font> = 0; - -<font color=red>/* The simple constructor and destructor don't do anything but give us - a place to expand in the future if we want. -*/</font> -<font color=#008888>Server::Server</font>(void) -{ - ; -} - -<font color=#008888>Server::~Server</font>(void) -{ - ; -} - -<font color=red>/* Opening the server is as simple as opening the acceptor with the - default ACE_Reactor instance. If we want to allow multiple - instances of Server objects then we should have an ACE_Reactor - member variable that we can register with. -*/</font> -int <font color=#008888>Server::open</font>(void) -{ - if (acceptor_.open (ACE_INET_Addr (ACE_DEFAULT_SERVER_PORT), <font color=#008888>ACE_Reactor::instance</font>()) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>open</font>"), -1); - - return(0); -} - -<font color=red>/* Running the server just means that we execute the basic event - loop for the reactor. Again, if we had a private reactor then we - could have multiple server's in their run() method. -*/</font> -int <font color=#008888>Server::run</font>(void) -{ - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) starting up server daemon\n</font>")); - - ACE_Time_Value timeout(2); - - <font color=red>// Here's the basic event loop. I have a 2-second timeout on</font> - <font color=red>// the handle_events() so that we don't have to wait too long</font> - <font color=red>// when we set the finished_ flag.</font> - while (!finished_) - { - <font color=#008888>ACE_Reactor::instance</font>()->handle_events (&timeout); - } - - <font color=red>// Close the acceptor when we're done. This may be handled by </font> - <font color=red>// the framework but it's good practice to be explicit about things.</font> - acceptor_.close(); - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) shutting down server daemon\n</font>")); - - return 0; -} - -<font color=red>/* The close() method simply sets the finished_ flag so that run() - will leave the event loop and exit. -*/</font> -int <font color=#008888>Server::close</font>(void) -{ - finished_ = 1; - return(0); -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page08.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page08.html b/docs/tutorials/015/page08.html deleted file mode 100644 index 951662c0191..00000000000 --- a/docs/tutorials/015/page08.html +++ /dev/null @@ -1,94 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -The Handler object is our event handler. You can use either -ACE_Event_Handler or ACE_Svc_Handler<> for the baseclass. I generally -prefer the latter since it takes care of some housekeeping that I -would otherwise be responsible for. -<P> -The class declaration is taken almost exactly from a previous -tutorial. A good design will have a simple handler object that will -collect data from the peer and pass it along to another object for -processing. Again, keep it simple and delegate authority. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#ifndef</font> <font color=purple>HANDLER_H</font> -<font color=blue>#define</font> <font color=purple>HANDLER_H</font> - -<font color=blue>#include</font> "<font color=green>ace/Svc_Handler.h</font>" - -<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>) -# pragma once -<font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font> - -<font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>" -<font color=blue>#include</font> "<font color=green>Protocol_Stream.h</font>" - -<font color=red>/* Just your basic event handler. We use ACE_Svc_Handler<> as a - baseclass so that it can maintain the peer() and other details for - us. We're not going to activate() this object, so we can get away - with the NULL synch choice. -*/</font> -class Handler : public ACE_Svc_Handler < ACE_SOCK_STREAM, ACE_NULL_SYNCH > -{ -public: - - Handler(void); - ~Handler(void); - - <font color=red>// Called by the acceptor when we're created in response to a</font> - <font color=red>// client connection.</font> - int open (void *); - - <font color=red>// Called when it's time for us to be deleted. We take care</font> - <font color=red>// of removing ourselves from the reactor and shutting down</font> - <font color=red>// the peer() connectin.</font> - void destroy (void); - - <font color=red>// Called when it's time for us to go away. There are subtle</font> - <font color=red>// differences between destroy() and close() so don't try to</font> - <font color=red>// use either for all cases.</font> - int close (u_long); - -protected: - - <font color=red>// Respond to peer() activity.</font> - int handle_input (ACE_HANDLE); - - <font color=red>// This will be called when handle_input() returns a failure</font> - <font color=red>// code. That's our signal that it's time to begin the</font> - <font color=red>// shutdown process.</font> - int handle_close(ACE_HANDLE, ACE_Reactor_Mask _mask); - -private: - - <font color=red>// Like the Client, we have to abide by the protocol</font> - <font color=red>// requirements. We use a local Protocol_Stream object to</font> - <font color=red>// take care of those details. For us, I/O then just becomes</font> - <font color=red>// a matter of interacting with the stream.</font> - Protocol_Stream stream_; - - Protocol_Stream & stream(void) - { - return this->stream_; - } -}; - -<font color=blue>#endif</font> <font color=red>// HANDLER_H</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page09.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page09.html b/docs/tutorials/015/page09.html deleted file mode 100644 index 246b24f75d1..00000000000 --- a/docs/tutorials/015/page09.html +++ /dev/null @@ -1,225 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -Like any other event handler, the handle_input() method will be -responsible for getting data from the peer() and doing something with -it. In this case, we have a Protocol_Stream to deal with. We'll use -the stream for the actual I/O but we are ultimately responsible for -processing the data from the peer. To do that, we've created a -Handler_Task that fits within the Protocol_Stream framework to process -data that has been received. Handler::handle_input() will tell the stream that -it's time to read data and that data will eventually show up at -Handler_Task::recv() where we'll process it as required by our -application logic. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#include</font> "<font color=green>Handler.h</font>" -<font color=blue>#include</font> "<font color=green>Protocol_Task.h</font>" - -<font color=red>/* The Protocol_Stream gives us the option to insert a Protocol_Task - to process data received by the stream. We'll get into the details - more when we talk about the stream in detail. For now it's enough - to know that <font color=#008888>Handler_Task::recv</font>() will be invoked by the stream - after data from the client has been received and processed (eg -- - decrypted, uncompressed, and whatever else the protocol requires.) -*/</font> -class Handler_Task : public Protocol_Task -{ -public: - - <font color=red>// Typical...</font> - typedef Protocol_Task inherited; - - <font color=red>// Simple...</font> - Handler_Task(void); - ~Handler_Task(void); - -protected: - - <font color=red>// recv() is invoked after received data has been fully</font> - <font color=red>// processed by the protocol rules. Data processing typically </font> - <font color=red>// done in handle_input() can then be done here.</font> - int recv(ACE_Message_Block * message, - ACE_Time_Value *timeout = 0); -}; - -<font color=#008888>Handler::Handler</font>(void) -{ - ; -} - -<font color=#008888>Handler::~Handler</font>(void) -{ - ; -} - -<font color=red>/* The Acceptor will open() us once the peer() connection is - established. There are a couple of things we have to do here - before we're ready to receive data from the client. -*/</font> -int <font color=#008888>Handler::open</font> (void *) -{ - ACE_INET_Addr addr; - - <font color=red>// Make sure that we can get the peer's address. If we can't</font> - <font color=red>// then there may be a network error or something else that</font> - <font color=red>// will prevent communicating with the client. This is</font> - <font color=red>// something you'll want to do in every event handler you create.</font> - if (this->peer ().get_remote_addr (addr) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) can't get remote addr\n</font>"), -1); - - <font color=red>// Announce the client</font> - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) connected with %s\n</font>", addr.get_host_name() )); - - <font color=red>// Here's the first new twist to the old event handler.</font> - <font color=red>// Before we can use the Protocol_Stream to communicate with</font> - <font color=red>// the peer, we must open() it. We provide the stream with</font> - <font color=red>// the peer() so that it will have a valid socket on which to</font> - <font color=red>// read client requests and send our responses. We also</font> - <font color=red>// provide a Handler_Task instance that will ultimately be</font> - <font color=red>// responsible for processing any client data we receive.</font> - int rval = stream().open( this->peer(), new Handler_Task() ); - - <font color=red>// Of course, we have to account for the chance that the</font> - <font color=red>// stream's open() may fail.</font> - if( rval == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) can't open the protocol stream.\n</font>"), -1); - } - - <font color=red>// Now that we know the client is valid and that the stream is </font> - <font color=red>// ready for business we can register with the gloabl reactor</font> - <font color=red>// instance. Here again is an opportunity for improvement if</font> - <font color=red>// we expect to have mulitple Server object instances.</font> - if (<font color=#008888>ACE_Reactor::instance</font>()->register_handler (this, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) can't register with reactor\n</font>"), -1); - - return rval; -} - -<font color=red>/* This is a fairly typical destroy() method that can be shared by - both close() and handle_close(). -*/</font> -void <font color=#008888>Handler::destroy</font> (void) -{ - <font color=#008888>ACE_Reactor::instance</font>()->remove_handler(this,ACE_Event_Handler::READ_MASK|ACE_Event_Handler::DONT_CALL); - - this->peer ().close (); - - delete this; -} - -<font color=red>/* In this simple application we just forward the close() and - handle_close() requests right on to the destroy() method. -*/</font> - -int <font color=#008888>Handler::close</font> (u_long) -{ - this->destroy (); - return 0; -} - -int <font color=#008888>Handler::handle_close</font>(ACE_HANDLE, ACE_Reactor_Mask _mask) -{ - this->destroy(); - return 0; -} - -<font color=red>/* Unlike a "<font color=green>traditional</font>" handle_input() ours is very simple. Because - of the use of the protocol stream, we delegate the read function to - the stream's get() and rely on our Handler_Task to do the real work. -*/</font> -int <font color=#008888>Handler::handle_input</font> (ACE_HANDLE) -{ - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) Activity from client\n</font>" )); - - <font color=red>// This will cause a blocking read from the peer(). The data</font> - <font color=red>// will then be pushed through the protocol stream.</font> - if( stream().get( ) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) can't get data from protocol stream\n</font>"), -1); - } - - return 0; -} - -<font color=red>/* A Protocol_Task is derived from ACE_Task and has the option of - running in one or more threads. I've chosen here to construct the - baseclass with no threads but it should work just fine with one or - more if you need. Unless you're sharing the Handler_Task with - several peers, however, you're probably just wasting a thread to - activate it. On the other hand, if your reactor is running in a - single thread (as in this example) then you can easily implement - thread-per-connectin concurrency by giving the baseclass one thread. -*/</font> -<font color=#008888>Handler_Task::Handler_Task</font>(void) - : inherited(0) -{ - ; -} - -<font color=#008888>Handler_Task::~Handler_Task</font>(void) -{ - ; -} - -<font color=red>/* When installed into the protocol stream, the Handler_Task's recv() - method will be called when data is ready for processing. - */</font> -int <font color=#008888>Handler_Task::recv</font>(ACE_Message_Block * message, - ACE_Time_Value *timeout ) -{ - <font color=red>// Announce the request we got from the client</font> - ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) <font color=#008888>Handler_Task::recv</font>() got (%s)\n</font>", message->rd_ptr() )); - - <font color=red>// Create a response message to send to the client</font> - ACE_Message_Block * response = new ACE_Message_Block( 128 ); - - <font color=red>// Nothing very original about this I'm afraid...</font> - <font color=#008888>ACE_OS::sprintf</font>( response->wr_ptr(), "<font color=green>You Said: (%s)</font>", message->rd_ptr() ); - response->wr_ptr( strlen(response->wr_ptr())+1 ); - - <font color=red>// Release the original message block now that we're through</font> - <font color=red>// "<font color=green>processing</font>" it.</font> - message->release(); - - <font color=red>// Turn the message around and send it back down the Stream.</font> - <font color=red>// In other words, we invoke the put() method on the</font> - <font color=red>// Protocol_Stream without having to have a direct reference</font> - <font color=red>// to the stream object.</font> - return this->reply( response, timeout ); -} -</PRE> -<HR> -<P> -That's it for the server-specific code. I think I've been fairly -successful in keeping it simple and to the point. There are a couple -of places where the as-yet-undescribed Protocol_Stream pops up and may -cause confusion. We're going to discuss that mystery now but before -we do here's the list of server files if you want to review: - -<UL> -<LI><A HREF="Makefile.server">Server Makefile</A> -<LI><A HREF="server.cpp">server.cpp</A> -<LI><A HREF="Server_i.h">Server_i.h</A> -<LI><A HREF="Server_i.cpp">Server_i.cpp</A> -<LI><A HREF="Handler.h">Handler.h</A> -<LI><A HREF="Handler.cpp">Handler.cpp</A> -</UL> -<P> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page10.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page10.html b/docs/tutorials/015/page10.html deleted file mode 100644 index 8f2c7ab55bf..00000000000 --- a/docs/tutorials/015/page10.html +++ /dev/null @@ -1,126 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -And so finally we come to the Protocol_Stream. That, after all, is -the focus of the entire tutorial but it took us half of the day to get -here! -<P> -The Protocol_Stream uses an ACE_Stream to move an ACE_Message_Block -through a series of tasks. Each task in the stream is responsible for -performing some operation on the data in the message block. That is -the nature of a protocol stream (or "stack" if you prefer). In this -stream, the data is compressed and encrypted* on its way between -peers. We also allow users of the stream to install a reader task to -handle data that percolates up from the peer. As you saw a page or -two ago, this is most useful for a server. - -<P> -<font size=-1>*Again, I just pretend to do these things. It would -take another day or two to go through any sort of reasonable -encryption or compression!</font> -<P> -Before we get into the code, here's a picture that's shows what's -going on here. -<P><center><img src="stream.gif"></center></p> -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#ifndef</font> <font color=purple>PROTOCOL_STREAM_H</font> -<font color=blue>#define</font> <font color=purple>PROTOCOL_STREAM_H</font> - -<font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>" - -<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>) -# pragma once -<font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font> - -<font color=blue>#include</font> "<font color=green>ace/Stream.h</font>" - -<font color=red>// Shorthand for the stream.</font> -typedef ACE_Stream<ACE_MT_SYNCH> Stream; - -<font color=red>// Forward references to cut down on the number of <font color=blue>#include</font>s</font> -class ACE_Message_Block; -class Recv; -class Protocol_Task; - -<font color=red>/* The Protocol_Stream provides a tidy interface to an ACE_Stream - setup to process a data block through a series of protocol stages. -*/</font> -class Protocol_Stream -{ -public: - Protocol_Stream(void); - ~Protocol_Stream(void); - - <font color=red>// Provide the stream with an ACE_SOCK_Stream on which it can</font> - <font color=red>// communicate. If _reader is non-null, it will be added as</font> - <font color=red>// the reader task just below the stream head so that it can</font> - <font color=red>// process data read from the peer.</font> - int open( ACE_SOCK_Stream & _peer, Protocol_Task * _reader = 0 ); - - <font color=red>// Close the stream. All of the tasks & modules will also be closed.</font> - int close(void); - - <font color=red>// putting data onto the stream will pass it through all</font> - <font color=red>// protocol levels and send it to the peer.</font> - int put( ACE_Message_Block * & _message, ACE_Time_Value * - _timeout = 0 ); - - <font color=red>// get will cause the Recv task (at the tail of the stream) to</font> - <font color=red>// read some data from the peer and pass it upstream. The</font> - <font color=red>// message block is then taken from the stream reader task's</font> - <font color=red>// message queue.</font> - int get( ACE_Message_Block * & _response, ACE_Time_Value * - _timeout = 0 ); - - <font color=red>// Tell the Recv task to read some data and send it upstream.</font> - <font color=red>// The data will pass through the protocol tasks and be queued</font> - <font color=red>// into the stream head reader task's message queue. If</font> - <font color=red>// you've installed a _reader in open() then that task's</font> - <font color=red>// recv() method will see the message and may consume it</font> - <font color=red>// instead of passing it to the stream head for queueing.</font> - int get(void); - - ACE_SOCK_Stream & peer(void) - { - return this->peer_; - } - -private: - <font color=red>// Our peer connection</font> - ACE_SOCK_Stream peer_; - - <font color=red>// The stream managing the various protocol tasks</font> - Stream stream_; - - <font color=red>// A task which is capable of receiving data on a socket.</font> - <font color=red>// Note that this is only useful by client-side applications.</font> - Recv * recv_; - - Stream & stream(void) - { - return this->stream_; - } - - <font color=red>// Install the protocol tasks into the stream.</font> - int open(void); -}; - -<font color=blue>#endif</font> <font color=red>// PROTOCOL_STREAM_H</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page11.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page11.html b/docs/tutorials/015/page11.html deleted file mode 100644 index 0ae929e8f7d..00000000000 --- a/docs/tutorials/015/page11.html +++ /dev/null @@ -1,195 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -And now the implementation of the Protocol_Stream. There are more -lines of code here than we've seen so far but it still isn't -complicated. The basic idea is to construct the ACE_Stream with our -set of protocol objects that will manipulate the data. Our primary -concern in this file is to get everything in the correct order! -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#include</font> "<font color=green>Protocol_Stream.h</font>" -<font color=blue>#include</font> "<font color=green>Protocol_Task.h</font>" - -<font color=blue>#include</font> "<font color=green>Xmit.h</font>" -<font color=blue>#include</font> "<font color=green>Recv.h</font>" - -<font color=blue>#include</font> "<font color=green>Compressor.h</font>" -<font color=blue>#include</font> "<font color=green>Crypt.h</font>" - -<font color=blue>#include</font> "<font color=green>ace/Stream_Modules.h</font>" - -<font color=red>/* You can choose at compile time to include/exclude the protocol - pieces. -*/</font> -<font color=blue>#define</font> <font color=purple>ENABLE_COMPRESSION</font> -<font color=blue>#define</font> <font color=purple>ENABLE_ENCRYPTION</font> - -<font color=red>// The usual typedefs to make things easier to type.</font> -typedef ACE_Module<ACE_MT_SYNCH> Module; -typedef ACE_Thru_Task<ACE_MT_SYNCH> Thru_Task; - -<font color=red>/* Do-nothing constructor and destructor - */</font> - -<font color=#008888>Protocol_Stream::Protocol_Stream</font>( void ) -{ - ; -} - -<font color=#008888>Protocol_Stream::~Protocol_Stream</font>( void ) -{ - ; -} - -<font color=red>/* Even opening the stream is rather simple. The important thing to - rememer is that the modules you push onto the stream first will be - at the tail (eg -- most downstream) end of things when you're - done. - */</font> -int <font color=#008888>Protocol_Stream::open</font>( ACE_SOCK_Stream & _peer, Protocol_Task * _reader ) -{ - <font color=red>// Initialize our peer() to read/write the socket we're given</font> - peer_.set_handle( _peer.get_handle() ); - - <font color=red>// Construct (and remember) the Recv object so that we can</font> - <font color=red>// read from the peer().</font> - recv_ = new Recv( peer() ); - - <font color=red>// Add the transmit and receive tasks to the head of the</font> - <font color=red>// stream. As we add more modules these will get pushed</font> - <font color=red>// downstream and end up nearest the tail by the time we're</font> - <font color=red>// done.</font> - if( stream().push( new Module( "<font color=green>Xmit/Recv</font>", new Xmit( peer() ), recv_ ) ) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>stream().push( xmit/recv )</font>"), -1); - } - - <font color=red>// Add any other protocol tasks to the stream. Each one is</font> - <font color=red>// added at the head. The net result is that Xmit/Recv are at </font> - <font color=red>// the tail.</font> - if( this->open() == -1 ) - { - return(-1); - } - - <font color=red>// If a reader task was provided then push that in as the</font> - <font color=red>// upstream side of the next-to-head module. Any data read</font> - <font color=red>// from the peer() will be sent through here last. Server</font> - <font color=red>// applications will typically use this task to do the actual</font> - <font color=red>// processing of data.</font> - <font color=red>// Note the use of Thru_Task. Since a module must always have </font> - <font color=red>// a pair of tasks we use this on the writter side as a no-op.</font> - if( _reader ) - { - if( stream().push( new Module( "<font color=green>Reader</font>", new Thru_Task(), _reader ) ) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>stream().push( reader )</font>"), -1); - } - } - - return(0); -} - -<font color=red>/* Add the necessary protocol objects to the stream. The way we're - pushing things on we will encrypt the data before compressing it. -*/</font> -int <font color=#008888>Protocol_Stream::open</font>(void) -{ -<font color=blue>#if defined</font>(<font color=purple>ENABLE_COMPRESSION</font>) - if( stream().push( new Module( "<font color=green>compress</font>", new Compressor(), new Compressor() ) ) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>stream().push( comprssor )</font>"), -1); - } -<font color=blue>#endif</font> <font color=red>// ENABLE_COMPRESSION</font> - -<font color=blue>#if defined</font>(<font color=purple>ENABLE_ENCRYPTION</font>) - if( stream().push( new Module( "<font color=green>crypt</font>", new Crypt(), new Crypt() ) ) == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green>stream().push( crypt )</font>"), -1); - } -<font color=blue>#endif</font> <font color=red>// ENABLE_ENCRYPTION</font> - return( 0 ); -} - -<font color=red>// Closing the Protocol_Stream is as simple as closing the ACE_Stream.</font> -int <font color=#008888>Protocol_Stream::close</font>(void) -{ - return stream().close(); -} - -<font color=red>// Simply pass the data directly to the ACE_Stream.</font> -int <font color=#008888>Protocol_Stream::put</font>(ACE_Message_Block * & _message, ACE_Time_Value * _timeout ) -{ - return stream().put(_message,_timeout); -} - -<font color=red>/* Tell the Recv module to read some data from the peer and pass it - upstream. Servers will typically use this method in a - handle_input() method to tell the stream to get a client's request. -*/</font> -int <font color=#008888>Protocol_Stream::get</font>(void) -{ - <font color=red>// If there is no Recv module, we're in big trouble!</font> - if( ! recv_ ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) No Recv object!\n</font>"), -1); - } - - <font color=red>// This tells the Recv module to go to it's peer() and read</font> - <font color=red>// some data. Once read, that data will be pushed upstream.</font> - <font color=red>// If there is a reader object then it will have a chance to</font> - <font color=red>// process the data. If not, the received data will be</font> - <font color=red>// available in the message queue of the stream head's reader</font> - <font color=red>// object (eg -- stream().head()->reader()->msg_queue()) and</font> - <font color=red>// can be read with our other get() method below.</font> - if( recv_->get() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) Cannot queue read request\n</font>"), -1); - } - - <font color=red>// For flexibility I've added an error() method to tell us if</font> - <font color=red>// something bad has happened to the Recv object.</font> - if( recv_->error() ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) Recv object error!\n</font>"), -1); - } - - return(0); -} - -<font color=red>/* Take a message block off of the stream head reader's message - queue. If the queue is empty, use get() to read from the peer. - This is most often used by client applications. Servers will - generaly insert a reader that will prevent the data from getting - all the way upstream to the head. -*/</font> -int <font color=#008888>Protocol_Stream::get</font>(ACE_Message_Block * & _response, ACE_Time_Value * _timeout ) -{ - if( stream().head()->reader()->msg_queue()->is_empty() ) - { - if( this->get() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>(%P|%t) Cannot get data into the stream.\n</font>"), -1); - } - } - - return stream().head()->reader()->getq(_response,_timeout); -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page12.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page12.html b/docs/tutorials/015/page12.html deleted file mode 100644 index 3731d2922ce..00000000000 --- a/docs/tutorials/015/page12.html +++ /dev/null @@ -1,98 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -And now the implementation of the Protocol_Stream. There are more -lines of code here than we've seen so far but it still isn't -complicated. The basic idea is to construct the ACE_Stream with our -set of protocol objects that will manipulate the data. Our primary -concern in this file is to get everything in the correct order! -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#ifndef</font> <font color=purple>PROTOCOL_TASK_H</font> -<font color=blue>#define</font> <font color=purple>PROTOCOL_TASK_H</font> - -<font color=blue>#include</font> "<font color=green>ace/Task.h</font>" - -<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>) -# pragma once -<font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font> - -<font color=red>/* A typical ACE_Task<> derivative that adds a few things appropriate - to protocol stacks. -*/</font> -class Protocol_Task : public ACE_Task<ACE_MT_SYNCH> -{ -public: - - typedef ACE_Task<ACE_MT_SYNCH> inherited; - - <font color=red>// A choice of concurrency strategies is offered by the</font> - <font color=red>// constructor. In most cases it makes sense to set this to</font> - <font color=red>// zero and let things proceed serially. You might have a</font> - <font color=red>// need, however, for some of your tasks to have their own thread.</font> - Protocol_Task( int _thr_count ); - - ~Protocol_Task(void); - - <font color=red>// open() is invoked when the task is inserted into the stream.</font> - virtual int open(void *arg); - - <font color=red>// close() is invoked when the stream is closed (flags will be</font> - <font color=red>// set to '1') and when the svc() method exits (flags will be</font> - <font color=red>// '0').</font> - virtual int close(u_long flags); - - <font color=red>// As data travels through the stream, the put() method of</font> - <font color=red>// each task is invoked to keep the data moving along.</font> - virtual int put(ACE_Message_Block *message, - ACE_Time_Value *timeout); - - <font color=red>// If you choose to activate the task then this method will be</font> - <font color=red>// doing all of the work.</font> - virtual int svc(void); - -protected: - - <font color=red>// Called by put() or svc() as necessary to process a block of</font> - <font color=red>// data.</font> - int process(ACE_Message_Block * message, ACE_Time_Value *timeout); - - <font color=red>// Just let us know if we're active or not.</font> - int is_active(void) - { - return this->thr_count() != 0; - } - - <font color=red>// Tasks on the writter (downstream) side of the stream</font> - <font color=red>// are called upon to send() data that will ultimately go to</font> - <font color=red>// the peer.</font> - virtual int send(ACE_Message_Block *message, - ACE_Time_Value *timeout); - - <font color=red>// Tasks on the reader (upstream) side will be receiving data</font> - <font color=red>// that came from the peer.</font> - virtual int recv(ACE_Message_Block * message, - ACE_Time_Value *timeout); - -private: - int desired_thr_count_; -}; - -<font color=blue>#endif</font> <font color=red>// PROTOCOL_TASK_H</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page13.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page13.html b/docs/tutorials/015/page13.html deleted file mode 100644 index da6fa97e0e5..00000000000 --- a/docs/tutorials/015/page13.html +++ /dev/null @@ -1,170 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -The Protocol_Task implementation takes care of the open(), close(), -put() and svc() methods so that derivatives can concentrate on the -send() and recv() methods. After a while you find that most -ACE_Task<> derivatives look very similar in the four basic methods and -only need one or two additional to do any real work. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#include</font> "<font color=green>Protocol_Task.h</font>" - -<font color=red>// Construct the object and remember the thread count.</font> -<font color=#008888>Protocol_Task::Protocol_Task</font>( int _thr_count ) - : desired_thr_count_(_thr_count) -{ -} - -<font color=#008888>Protocol_Task::~Protocol_Task</font>(void) -{ -} - -<font color=red>// Activate the object if necessary.</font> -int <font color=#008888>Protocol_Task::open</font>(void *arg) -{ - ACE_UNUSED_ARG(arg); - - if( desired_thr_count_ ) - { - return this->activate(THR_NEW_LWP, desired_thr_count_); - } - - return(0); -} - -<font color=red>/* When we're being closed by the ACE_Stream and we've got threads to - worry about then we drop a hangup message onto the message queue so - that svc() will go away. Except for the call to is_active(), this - is lifted directly from Tutorial 14. -*/</font> -int <font color=#008888>Protocol_Task::close</font>(u_long flags) -{ - if (flags == 1 && is_active() ) - { - ACE_Message_Block *hangupBlock = new ACE_Message_Block(); - - hangupBlock->msg_type(<font color=#008888>ACE_Message_Block::MB_HANGUP</font>); - - if (this->putq(hangupBlock->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Task::close</font>() putq</font>"), -1); - } - - hangupBlock->release(); - - return this->wait(); - } - - return 0; -} - -<font color=red>/* The put() method has to make a decision. If we've got threads then - put the unit of work onto the message queue for svc() to deal - with. If not then process() it directly. -*/</font> -int <font color=#008888>Protocol_Task::put</font>(ACE_Message_Block *message,ACE_Time_Value *timeout) -{ - if( is_active() ) - { - return this->putq(message,timeout); - } - - return this->process(message,timeout); -} - -<font color=red>/* svc() is about what you would expect. This is again lifted - directly from Tutorial 14 but with a call to process() for handling - the logic instead of doing the work right here. - */</font> -int <font color=#008888>Protocol_Task::svc</font>(void) -{ - ACE_Message_Block * message; - - while (1) - { - <font color=red>// Get a message</font> - if ( this->getq(message, 0) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Protocol_Task::svc</font>() getq</font>"), -1); - } - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) <font color=#008888>Protocol_Task::svc</font>() got message\n</font>")); - - <font color=red>// Check for hangup</font> - if (message->msg_type() == <font color=#008888>ACE_Message_Block::MB_HANGUP</font>) { - - ACE_DEBUG ((LM_DEBUG, "<font color=green>(%P|%t) <font color=#008888>Protocol_Task::svc</font>() -- HANGUP block received\n</font>")); - - <font color=red>// Hangup our thread-pool peers (if any)</font> - if (this->putq(message->duplicate()) == -1) { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Protocol_Task::svc</font>() putq</font>"), -1); - } - - <font color=red>// Leave svc()</font> - break; - } - - <font color=red>// Do some work on the data.</font> - if( this->process(message->duplicate(),0) == -1 ) - { - break; - } - - <font color=red>// Give up the message block before we go get another.</font> - message->release(); - } - - <font color=red>// Give up the message block that caused us to exit the</font> - <font color=red>// while(1) loop.</font> - message->release(); - - return(0); -} - -<font color=red>/* There's nothing really magic about process(). We just decide if - we're moving data upstream or downstream and invoke the appropriate - virtual function to handle it. -*/</font> -int <font color=#008888>Protocol_Task::process</font>(ACE_Message_Block * message, ACE_Time_Value *timeout) -{ - if( this->is_writer() ) - { - return this->send(message,timeout); - } - - return this->recv(message,timeout); -} - -<font color=red>/* We must insist that derivatives provide a meaningful overload for - these methods. It's fairly common for ACE object methods to return - an error when an overload is expected but the method cannot be - safely made pure virtual. - */</font> - -int <font color=#008888>Protocol_Task::send</font>(ACE_Message_Block *message, - ACE_Time_Value *timeout) -{ - return -1; -} - -int <font color=#008888>Protocol_Task::recv</font>(ACE_Message_Block * message, - ACE_Time_Value *timeout) -{ - return -1; -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page14.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page14.html b/docs/tutorials/015/page14.html deleted file mode 100644 index 7a5016ba090..00000000000 --- a/docs/tutorials/015/page14.html +++ /dev/null @@ -1,77 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -The Xmit object knows how to send data to the peer. It sits at the -tail of the stream and gets everything that flows down from the head. -In keeping with the spirit of things, this object does only one thing -and doesn't concern itself with anyone else' details. -<P> -The only thing you might want to do is combine it with Recv. Why? -As you'll realize in a page or two, the Xmit and Recv objects must -interact if you're going to ensure a safe transit. By having a single -object it's easier to coordinate and maintain the interaction. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#ifndef</font> <font color=purple>XMIT_H</font> -<font color=blue>#define</font> <font color=purple>XMIT_h</font> - -<font color=blue>#include</font> "<font color=green>Protocol_Task.h</font>" - -<font color=red>// Forward reference reduces <font color=blue>#include</font> dependencies</font> -class ACE_SOCK_Stream; - -<font color=red>/* A class suitable for sending data to a peer from within an - ACE_Stream. - */</font> -class Xmit : public Protocol_Task -{ -public: - - typedef Protocol_Task inherited; - - <font color=red>// We must be given a valid peer when constructed. Without that</font> - <font color=red>// we don't know who to send data to.</font> - Xmit( ACE_SOCK_Stream & _peer ); - - ~Xmit(void); - - <font color=red>// As you know, close() will be called in a couple of ways by the</font> - <font color=red>// ACE framework. We use that opportunity to terminate the</font> - <font color=red>// connection to the peer.</font> - int close(u_long flags); - -protected: - - ACE_SOCK_Stream & peer(void) - { - return this->peer_; - } - - <font color=red>// Send the data to the peer. By now it will have been</font> - <font color=red>// completely protocol-ized by other tasks in the stream.</font> - int send(ACE_Message_Block *message, - ACE_Time_Value *timeout); - -private: - <font color=red>// A representation of the peer we're talking to.</font> - ACE_SOCK_Stream & peer_; -}; - -<font color=blue>#endif</font> <font color=red>// XMIT_H</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page15.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page15.html b/docs/tutorials/015/page15.html deleted file mode 100644 index 708e19b7183..00000000000 --- a/docs/tutorials/015/page15.html +++ /dev/null @@ -1,118 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -The implementation of Xmit isn't too complicated. If we choose to -combine it with the Recv task we simply lift the recv() method from -that object and drop it into this one. -<P> -Note that close() must decide if it's being called when the stream is -shutdown or when it's svc() method exits. Since we tell the baseclass -not to use any threads it's a safe bet that flags will always be -non-zero. Still, it's good practice to plan for the future by -checking the value. -<P> -Note also that when we send the data we prefix it with the data size. -This let's our sibling Recv ensure that an entire block is received -together. This can be very important for compression and encryption -processes which typically work better with blocks of data instead of -streams of data. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#include</font> "<font color=green>Xmit.h</font>" -<font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>" - -<font color=red>/* Construct the object with the peer connection and choose not to - activate ourselves into a dedicated thread. You might get some - performance gain by activating but if you really want a - multi-threaded apprroach you should handle that as a separate - issue. Attempting to force threading at this level will likely - cause more trouble than you want to deal with. -*/</font> -<font color=#008888>Xmit::Xmit</font>( ACE_SOCK_Stream & _peer ) - : inherited(0), peer_(_peer) -{ -} - -<font color=#008888>Xmit::~Xmit</font>(void) -{ -} - -<font color=red>/* Check to see if we're being closed by the stream (flags != 0) or if - we're responding to the exit of our svc() method. -*/</font> -int <font color=#008888>Xmit::close</font>(u_long flags) -{ - <font color=red>// Take care of the baseclass closure.</font> - int rval = <font color=#008888>inherited::close</font>(flags); - - <font color=red>// Only if we're being called at the stream shutdown do we close</font> - <font color=red>// the peer connection. If, for some reason, we were activated</font> - <font color=red>// into one or more threads we wouldn't want to close the pipe</font> - <font color=red>// before all threads had a chance to flush their data.</font> - if( flags ) - { - peer().close(); - } - - return( rval ); -} - -<font color=red>/* Our overload of send() will take care of sending the data to the - peer. -*/</font> -int <font color=#008888>Xmit::send</font>(ACE_Message_Block *message, ACE_Time_Value *timeout) -{ - int rval; - - ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) <font color=#008888>Xmit::send</font>() sending (%s)(%d)\n</font>", message->rd_ptr(), message->length() )); - - <font color=red>/* Since we're going to be sending data that may have been - compressed and encrypted it's probably important for the - receiver to get an entire "<font color=green>block</font>" instead of having a - partial read. - - For that reason, we'll send the length of the message block - (in clear-text) to the peer so that it can then recv_n() - the entire block contents in one read operation. - */</font> - char msize[32]; - sprintf(msize,"<font color=green>%d</font>",message->length()); - - <font color=red>// Be sure we send the end-of-string NULL so that Recv will</font> - <font color=red>// know when to stop assembling the length.</font> - rval = this->peer().send_n( msize, strlen(msize)+1, 0, timeout ); - - if( rval == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Xmit::send</font>() Failed to send message size.</font>"), -1); - } - - <font color=red>/* Now we send the actual data. If you're worried about - network efficiency then you may choose to create one buffer - containing msize and the message data and send it all at - once. - */</font> - rval = this->peer().send_n( message->rd_ptr(), message->length(), 0, timeout ); - - <font color=red>// Release the message block since we're done with it.</font> - message->release(); - - return( rval ); -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page16.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page16.html b/docs/tutorials/015/page16.html deleted file mode 100644 index 620950ad548..00000000000 --- a/docs/tutorials/015/page16.html +++ /dev/null @@ -1,93 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -Recv is the sibling to Xmit. Again, they could be combined into a -single object if you want. -<P> -An ACE_Stream is designed to handle downstream traffic very -well. You put() data into it and it flows along towards the tail. -However, there doesn't seem to be a way to put data in such that it -will travel upstream. To get around that, I've added a get() method -to Recv that will trigger a read on the socket. Recv will then put -the data to the next upstream module and we're on our way. As noted -earlier, that data will eventually show up either in the <i>reader</i> -(if installed on the stream open()) or the stream head reader task's -message queue. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#ifndef</font> <font color=purple>RECV_H</font> -<font color=blue>#define</font> <font color=purple>RECV_h</font> - -<font color=blue>#include</font> "<font color=green>Protocol_Task.h</font>" - -class ACE_SOCK_Stream; - -<font color=red>/* Get some data from the peer and send it upstream for - de-protocol-ization. -*/</font> -class Recv : public Protocol_Task -{ -public: - - typedef Protocol_Task inherited; - - <font color=red>// Give it someone to talk to...</font> - Recv( ACE_SOCK_Stream & _peer ); - - ~Recv(void); - - <font color=red>// Trigger a read from the socket</font> - int get(void); - - <font color=red>// In some cases it might be easier to check the "<font color=green>state</font>" of the</font> - <font color=red>// Recv object than to rely on return codes filtering back to</font> - <font color=red>// you.</font> - int error(void) - { - return this->error_; - } - -protected: - - ACE_SOCK_Stream & peer(void) - { - return this->peer_; - } - - <font color=red>// The baseclass will trigger this when our get() method is</font> - <font color=red>// called. A message block of the appropriate size is created,</font> - <font color=red>// filled and passed up the stream.</font> - int recv(ACE_Message_Block * message, - ACE_Time_Value *timeout = 0); - -private: - <font color=red>// Our endpoint</font> - ACE_SOCK_Stream & peer_; - - <font color=red>// get() uses a bogus message block to cause the baseclass to</font> - <font color=red>// invoke recv(). To avoid memory thrashing, we create that</font> - <font color=red>// bogus message once and reuse it for the life of Recv.</font> - ACE_Message_Block * tickler_; - - <font color=red>// Our error flag (duh)</font> - int error_; -}; - -<font color=blue>#endif</font> <font color=red>// RECV_H</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page17.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page17.html b/docs/tutorials/015/page17.html deleted file mode 100644 index d506014a77d..00000000000 --- a/docs/tutorials/015/page17.html +++ /dev/null @@ -1,108 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -The Recv implementation is nearly as simple as Xmit. There's -opportunity for error when we get the message size and we have to -manage the lifetime of the tickler but other than that it's pretty -basic stuff. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#include</font> "<font color=green>Recv.h</font>" -<font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>" - -<font color=red>/* Construct the object with the peer reference and other appropriate - initializations. -*/</font> -<font color=#008888>Recv::Recv</font>( ACE_SOCK_Stream & _peer ) - : inherited(0), peer_(_peer), error_(0) -{ - <font color=red>// Create the tickler that get() will use to trigger recv()</font> - <font color=red>// through the baseclass. Since we're single-threaded this is</font> - <font color=red>// probably overkill but it makes multi-threading easier if we</font> - <font color=red>// choose to do that.</font> - tickler_ = new ACE_Message_Block(1); -} - -<font color=red>/* Be sure we manage the lifetime of the tickler to prevent a memory - leak. -*/</font> -<font color=#008888>Recv::~Recv</font>(void) -{ - tickler_->release(); -} - -<font color=red>/* By putting the tickler to ourselves we cause things to happen in - the baseclass that will invoke recv(). If we know we're single - threaded we could directly call recv() and be done with it but then - we'd have to do something else if we're multi-threaded. Just let - the baseclass worry about those things! -*/</font> -int <font color=#008888>Recv::get</font>(void) -{ - return this->put( tickler_, 0 ); -} - -int <font color=#008888>Recv::recv</font>(ACE_Message_Block * message, ACE_Time_Value *timeout) -{ - int rval; - - <font color=red>/* Xmit will send us the message length in clear-text. I - assume that will be less than 32-bytes! - */</font> - char msize[32]; - int b = 0; - - <font color=red>/* Read from the socket one byte at a time until we see then - end-of-string NULL character. Since the OS layers (at leas - in Unix) will provide some buffering this isn't as bad as - it may seem at first. - */</font> - do - { - rval = this->peer().recv( &msize[b], 1, timeout ); - if( rval == -1 ) - { - error_ = 1; - ACE_ERROR_RETURN ((LM_ERROR, "<font color=green>%p\n</font>", "<font color=green><font color=#008888>Recv::recv</font>() Failed to get message size.</font>"), -1); - } - } - while( msize[b++] != 0 ); - - int size = atoi(msize); - - <font color=red>// Make a block big enough to contain the data we'll read</font> - message = new ACE_Message_Block( size ); - - <font color=red>// Read the actual message data into our new message block</font> - rval = this->peer().recv_n( message->wr_ptr(), size, 0, timeout ); - - <font color=red>// If we got the data correctly then send it on upstream.</font> - if( rval > 0 ) - { - message->wr_ptr( rval ); - return( this->put_next( message ) ); - } - - <font color=red>// Something bad happend on the recv_n(). Set an error flag</font> - <font color=red>// and return error.</font> - error_ = 1; - - return( -1 ); -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page18.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page18.html b/docs/tutorials/015/page18.html deleted file mode 100644 index 1941734eb49..00000000000 --- a/docs/tutorials/015/page18.html +++ /dev/null @@ -1,68 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -This and the next three pages present the protocol objects that -provide compression and encryption. If you were hoping to learn the -secrets of compression and encryption then I'm going to disappoint -you. There are some really good libraries out there that do this -stuff though and if anyone wants to integrate one of them into the -tutorial I'll be glad to take it! -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#ifndef</font> <font color=purple>COMPRESSOR_H</font> -<font color=blue>#define</font> <font color=purple>COMPRESSOR_h</font> - -<font color=blue>#include</font> "<font color=green>Protocol_Task.h</font>" - -<font color=red>/* A reallly dumb compression object. (It actually adds 3 bytes to - every message block.) -*/</font> -class Compressor : public Protocol_Task -{ -public: - - typedef Protocol_Task inherited; - - <font color=red>// I've given you the option of creating this task derivative</font> - <font color=red>// with a number of threads. In retro-spect that really isn't</font> - <font color=red>// a good idea. Most client/server systems rely on requests</font> - <font color=red>// and responses happening in a predicatable order. Introduce</font> - <font color=red>// a thread pool and message queue and that ordering goes</font> - <font color=red>// right out the window. In other words: Don't ever use the</font> - <font color=red>// constructor parameter!</font> - Compressor( int _thr_count = 0 ); - - ~Compressor(void); - -protected: - - <font color=red>// This is called when the compressor is on the downstream</font> - <font color=red>// side. We'll take the message, compress it and move it</font> - <font color=red>// along to the next module.</font> - int send(ACE_Message_Block *message, - ACE_Time_Value *timeout); - - <font color=red>// This one is called on the upstream side. No surprise: we</font> - <font color=red>// decompress the data and send it on up the stream.</font> - int recv(ACE_Message_Block *message, - ACE_Time_Value *timeout); -}; - -<font color=blue>#endif</font> <font color=red>// COMPRESSOR_H</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page19.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page19.html b/docs/tutorials/015/page19.html deleted file mode 100644 index 73103ff15bf..00000000000 --- a/docs/tutorials/015/page19.html +++ /dev/null @@ -1,119 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -Here we implement the details of our compression. By having both -compression and decompression in one object it's easier to keep track -of implementation details. Splitting Xmit/Recv like I did will make -things more difficult if something has to change in their interaction. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#include</font> "<font color=green>Compressor.h</font>" -<font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>" - -<font color=red>/* Construct our baseclass with the proper thread count. I really - should remove this option... - */</font> -<font color=#008888>Compressor::Compressor</font>( int _thr_count ) - : inherited(_thr_count) -{ - ; -} - -<font color=#008888>Compressor::~Compressor</font>(void) -{ - ; -} - -<font color=red>/* This is where you insert your compression code. Most compressors - want to work on a block of data instead of a byte-stream. - Fortunately the message block has a block that can be compressed. - Take a look at libz for a quick way to add compression to your - apps - */</font> -int <font color=#008888>Compressor::send</font>(ACE_Message_Block *message, ACE_Time_Value *timeout) -{ - ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) <font color=#008888>Compressor::send</font>() compressing (%s)\n</font>", message->rd_ptr() )); - - <font color=red>// Create a block to hold the compressed data. I belive libz</font> - <font color=red>// recommends a buffer about 10-20% larger than the source.</font> - <font color=red>// Other libraries/algorithms may have their own quirks.</font> - ACE_Message_Block * compressed = new ACE_Message_Block( message->size() ); - - <font color=red>// Perform a bogus compression algorithm. 'CD' just tells me</font> - <font color=red>// that this is compressed data and when we "<font color=green>decompress</font>" we'll </font> - <font color=red>// look for this signature to validate the data received.</font> - <font color=#008888>ACE_OS::sprintf</font>( compressed->wr_ptr(), "<font color=green>CD:%s</font>", message->rd_ptr() ); - compressed->wr_ptr( strlen(compressed->wr_ptr())+1 ); - - <font color=red>// Send the compressed data down the stream to the next module</font> - this->put_next( compressed ); - - <font color=red>// We're done here.</font> - message->release(); - - return( 0 ); -} - -<font color=red>/* And here's the decompression side. We've written Xmit/Recv so that - we're guaranteed to get an entire block of compressed data. If - we'd used recv() in the Recv object then we might have gotten a - partial block and that may not decompress very nicely. - */</font> -int <font color=#008888>Compressor::recv</font>(ACE_Message_Block *message, ACE_Time_Value *timeout) -{ - ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) <font color=#008888>Compress::recv</font>() decompressing (%s)\n</font>", message->rd_ptr() )); - - <font color=red>// Room for the decompressed data. In the real world you</font> - <font color=red>// would probably want to send the original (uncompressed)</font> - <font color=red>// data size in the message. You can predict the maximum</font> - <font color=red>// possible decompression size but it's cheap and easy just to </font> - <font color=red>// send that along. Look again at how I do exacly that</font> - <font color=red>// between Xmit and Recv.</font> - ACE_Message_Block * decompressed = new ACE_Message_Block( message->size() ); - - <font color=red>// Check for our signature. Even when you use a real</font> - <font color=red>// compression algorithm you may want to include your own</font> - <font color=red>// signature so that you can verify the block. It pays to be</font> - <font color=red>// paranoid!</font> - if( <font color=#008888>ACE_OS::strncmp</font>( message->rd_ptr(), "<font color=green>CD:</font>", 3 ) ) - { - ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) Improperly encompressed data.\n</font>" )); - message->release(); - return(-1); - } - - <font color=red>// Skip past the signature before going any further.</font> - message->rd_ptr( 3 ); - - <font color=red>// Perform a bogus decompression algorithm. This is where you </font> - <font color=red>// would feed to libz or your favorite decompressor. (It's</font> - <font color=red>// costly but you could invoke popen() on gzip!)</font> - <font color=#008888>ACE_OS::sprintf</font>( decompressed->wr_ptr(), "<font color=green>%s</font>", message->rd_ptr() ); - decompressed->wr_ptr( strlen(decompressed->wr_ptr())+1 ); - - <font color=red>// Recv the decompressed data down the stream to the next module</font> - this->put_next( decompressed ); - - <font color=red>// We're done here.</font> - message->release(); - - return( 0 ); -} - -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page20.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page20.html b/docs/tutorials/015/page20.html deleted file mode 100644 index 6a26fd24fad..00000000000 --- a/docs/tutorials/015/page20.html +++ /dev/null @@ -1,61 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -While I might be able to come up with a competitive compressor, I -don't have a snowball's chance to code up encryption. I'd be better -off piping the data through the standard Unix crypt command. -<P> -So, while I was lazy with Compress, I'm realistic with Crypt. I'll -show you the hooks and entry points and let someone else contribute an -encryptor. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#ifndef</font> <font color=purple>CRYPT_H</font> -<font color=blue>#define</font> <font color=purple>CRYPT_h</font> - -<font color=blue>#include</font> "<font color=green>Protocol_Task.h</font>" - -<font color=red>/* An interface (adaptor) between your favorite encryption method and - an ACE_Stream. -*/</font> -class Crypt : public Protocol_Task -{ -public: - - typedef Protocol_Task inherited; - - <font color=red>// Again we have the option of multiple threads and again I</font> - <font color=red>// regret tempting folks to use it.</font> - Crypt( int _thr_count = 0 ); - - ~Crypt(void); - -protected: - - <font color=red>// Moving downstream will encrypt the data</font> - int send(ACE_Message_Block *message, - ACE_Time_Value *timeout); - - <font color=red>// And moving upstream will decrypt it.</font> - int recv(ACE_Message_Block *message, - ACE_Time_Value *timeout); -}; - -<font color=blue>#endif</font> <font color=red>// CRYPT_H</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page21.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page21.html b/docs/tutorials/015/page21.html deleted file mode 100644 index 5b017dcf609..00000000000 --- a/docs/tutorials/015/page21.html +++ /dev/null @@ -1,99 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -The encryption implementation isn't any smarter than that of the -compressor. Still, the hooks are there for you to insert your -favorite library. -<HR> -<PRE> - -<font color=red>// $Id$</font> - -<font color=blue>#include</font> "<font color=green>Crypt.h</font>" -<font color=blue>#include</font> "<font color=green>ace/SOCK_Stream.h</font>" - -<font color=red>/* The expected constructor... - */</font> -<font color=#008888>Crypt::Crypt</font>( int _thr_count ) - : inherited(_thr_count) -{ -} - -<font color=#008888>Crypt::~Crypt</font>(void) -{ -} - -<font color=red>/* To send the data we'll apply a signature and encryption. - */</font> -int <font color=#008888>Crypt::send</font>(ACE_Message_Block *message, ACE_Time_Value *timeout) -{ - ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) <font color=#008888>Crypt::send</font>() encrypting (%s)\n</font>", message->rd_ptr() )); - - <font color=red>// I suspect that some encryptors might change the data size.</font> - <font color=red>// It probably isn't safe to create a same-size destination buffer.</font> - ACE_Message_Block * encrypted = new ACE_Message_Block( message->size() ); - - <font color=red>// Perform a bogus encryption algorithm and add our safety</font> - <font color=red>// signature. Adding the original data size is also probably</font> - <font color=red>// a good idea that I haven't encorporated here.</font> - <font color=#008888>ACE_OS::sprintf</font>( encrypted->wr_ptr(), "<font color=green>ED:%s</font>", message->rd_ptr() ); - encrypted->wr_ptr( strlen(encrypted->wr_ptr())+1 ); - - <font color=red>// Send the encrypted data down the stream to the next module</font> - this->put_next( encrypted ); - - <font color=red>// We're done here.</font> - message->release(); - - return( 0 ); -} - -<font color=red>/* The upstream movement requires that we decrypt what the peer has - given us. -*/</font> -int <font color=#008888>Crypt::recv</font>(ACE_Message_Block *message, ACE_Time_Value *timeout) -{ - ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) <font color=#008888>Crypt::recv</font>() decrypting (%s)\n</font>", message->rd_ptr() )); - - <font color=red>// Create a destination for the decrypted data. The same</font> - <font color=red>// block size caveat exists of course.</font> - ACE_Message_Block * decrypted = new ACE_Message_Block( message->size() ); - - <font color=red>// Check the signature as expected.</font> - if( <font color=#008888>ACE_OS::strncmp</font>( message->rd_ptr(), "<font color=green>ED:</font>", 3 ) ) - { - ACE_DEBUG ((LM_INFO, "<font color=green>(%P|%t) Improperly encrypted data.\n</font>" )); - message->release(); - return(-1); - } - - <font color=red>// Don't forget to skip past the signature before decrypting</font> - <font color=red>// or things will be quite exciting!</font> - message->rd_ptr( 3 ); - - <font color=red>// Perform a bogus decryption algorithm</font> - <font color=#008888>ACE_OS::sprintf</font>( decrypted->wr_ptr(), "<font color=green>%s</font>", message->rd_ptr() ); - decrypted->wr_ptr( strlen(decrypted->wr_ptr())+1 ); - - <font color=red>// Send the decrypted data down the stream to the next module</font> - this->put_next( decrypted ); - - <font color=red>// We're done here.</font> - message->release(); - - return( 0 ); -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page22.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/015/page22.html b/docs/tutorials/015/page22.html deleted file mode 100644 index 90843ab2d31..00000000000 --- a/docs/tutorials/015/page22.html +++ /dev/null @@ -1,82 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>ACE Tutorial 015</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 015</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Building a protocol stream</FONT></B></CENTER> - -<P> -<HR WIDTH="100%"> -Well, this has certainly been one of the more verbose tutorials to -date. I must say "thanks" to everyone who stuck it out this far! -<P> -A quick review of what we've done: -<UL> - -<LI>Create a simple client application and Client object that uses a -Protocol Stream without really knowing how they work. The app (and -object) rely on the public interface of the Protocol Stream to get the -job done. At this level the protocol details are irrelevant. -<P> -<LI>Next, we create a simple server application and Server object -similar to the client. The Protocol Stream is of course used and we -have to know a little more so that we can insert a <i>reader</i> that -will ultimately process the data from the client. -<P> -<LI>We then go into the details of the Protocol_Stream implementation -and it's Protocol_Task object that forms the basis for the stream -tasks. Each object is kept as small and simple as possible to improve -reusability and future maintenance. -<P> -<LI>Finally, the individual protocol objects are discused. Separate -objects for the peer interface were created as well as the bogus -compressor and encryptor. The protocol can be extended or modified by -creating new such objects and installing them in the Protocol_Stream's -open() method. - -</UL> -<P> - -It doesn't sound like much but it certainly took a bunch of files to -get there. It's easy to get lost in the details when there's so much -to cover so you're encouraged to go over things a couple of times. -As always, enhancments of the tutorials is welcome! -<P> -Here's the complete file list: -<UL> -<LI><A HREF="client">Makefile</A> -<P> -<LI><A HREF="Makefile.client">client Makefile</A> -<LI><A HREF="client.cpp">client.cpp</A> -<LI><A HREF="Client.h">Client.h</A> -<LI><A HREF="Client.cpp">Client.cpp</A> -<P> -<LI><A HREF="Makefile.server">Server Makefile</A> -<LI><A HREF="server.cpp">server.cpp</A> -<LI><A HREF="Server.h">Server.h</A> -<LI><A HREF="Server.cpp">Server.cpp</A> -<LI><A HREF="Handler.h">Handler.h</A> -<LI><A HREF="Handler.cpp">Handler.cpp</A> -<P> -<LI><A HREF="Protocol_Stream.cpp">Protocol_Stream.cpp</A> -<LI><A HREF="Protocol_Stream.h">Protocol_Stream.h</A> -<LI><A HREF="Protocol_Task.cpp">Protocol_Task.cpp</A> -<LI><A HREF="Protocol_Task.h">Protocol_Task.h</A> -<P> -<LI><A HREF="Xmit.cpp">Xmit.cpp</A> -<LI><A HREF="Xmit.h">Xmit.h</A> -<LI><A HREF="Recv.cpp">Recv.cpp</A> -<LI><A HREF="Recv.h">Recv.h</A> -<P> -<LI><A HREF="Compressor.cpp">Compressor.cpp</A> -<LI><A HREF="Compressor.h">Compressor.h</A> -<LI><A HREF="Crypt.cpp">Crypt.cpp</A> -<LI><A HREF="Crypt.h">Crypt.h</A> -</UL> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] </CENTER> diff --git a/docs/tutorials/015/server.cpp b/docs/tutorials/015/server.cpp deleted file mode 100644 index bface44e341..00000000000 --- a/docs/tutorials/015/server.cpp +++ /dev/null @@ -1,46 +0,0 @@ - -// $Id$ - -#include "Server_i.h" - -// A signal handler that will close the server object -extern "C" void handler (int) -{ - Server::close(); -} - -int main (int, char **) -{ - // The server object that abstracts away all of difficult parts. - Server server; - - // Attempt to open the server. Like all good ACE-based - // objects, we'll get -1 on failure. - if( server.open() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "server.open()"), -1); - } - - // Install a signal handler for ^C so that we can exit gracefully - ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - // Run the server's main loop until we're interrupted - if( server.run() == -1 ) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "server.run()"), -1); - } - - return 0; -} - -/* These explicit instantiations were taken from an earlier tutorial. - Your compiler may require others as well. -*/ -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ - diff --git a/docs/tutorials/015/stream.gif b/docs/tutorials/015/stream.gif Binary files differdeleted file mode 100644 index daae2420b74..00000000000 --- a/docs/tutorials/015/stream.gif +++ /dev/null diff --git a/docs/tutorials/Makefile b/docs/tutorials/Makefile deleted file mode 100644 index f1887ccbef9..00000000000 --- a/docs/tutorials/Makefile +++ /dev/null @@ -1,8 +0,0 @@ - -# $Id$ - -all clean realclean : # - for i in * ; do \ - [ -f $$i/Makefile ] || continue ; \ - ( cd $$i ; $(MAKE) $@ ) ; \ - done diff --git a/docs/tutorials/combine b/docs/tutorials/combine deleted file mode 100755 index bf2372816f2..00000000000 --- a/docs/tutorials/combine +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/perl -# -# This perl script will combine a set of files into one or more HTML pages. -# -# The file fooNN.html will be created by combining the files: -# fooNN.hdr -# fooNN.pre -# fooNN.bdy -# fooNN.pst -# -# Where NN is a 2-digit number. If fooNN.hdr does not exist, the file 'hdr' -# will be used. If any of the other file-parts don't exist, they will be -# ignored. -# -# Usage: -# combine *.html -# combine *.pre -# -# Input files: -# -# -# hdr -# If no *.hdr exists for the current page, this is used. You will typically -# use this to add <TITLE> and such to each page created. -# -# *.hdr -# You can override the generic hdr you create by creating one for -# a specific page. -# -# *.pre -# Prefix files. Their content is included after the hdr. -# -# *.bdy -# Body files follow prefix. You generally use the links file to create -# links between source-code and a bdy filename. The bdy files are -# examined and "fontified" (think emacs). -# -# bodies -# The list of files to use for the body of the HTML pages generated -# -# *.pst -# Post files. This content follows the bdy content. -# -# *.html -# These are the output. If they exist before you run combine, they -# will be overwritten. -# -use File::Copy; - -%format = (); - -$PAGE=0; - -open(LINKS,"<bodies") || die; -while( ($file = <LINKS>) ) { - - chomp($file); - - next if( $file =~ /^#/ || $file eq '' ); - - - if( $file =~ /^.*=/ ) { - ($var,$value) = split(/=/,$file); - if( $var =~ /PAGE/ ) { - $PAGE = $value + 0; - } - next; - } - - $body{$PAGE++} = "$file"; -} -close(LINKS); - -foreach $file (@ARGV) { - ($base = $file) =~ s/.html$//; - $base =~ s/.pre$//; - - open(FILE,">$base.html") || die; - select(FILE); - $| = 1; - - # .hdr has the HTML header, title, etc... - if( -f "$base.hdr" ) { - copy("$base.hdr",\*FILE); - } - elsif( -f "hdr" ) { - copy("hdr",\*FILE); - } - # .pre has the discussion of what you'll see on this page - if( -f "$base.pre" ) { - copy("$base.pre",\*FILE); - } - # .bdy is the body of the page - if( -f "$base.bdy" ) { - &addFile("$base.bdy"); - } - - ($num = $base) =~ s/[A-z]//g; - $num += 0; - - if( -f "$body{$num}" ) { - &addFile("$body{$num}"); - } - # .pst summarizes what was seen - if( -f "$base.pst" ) { - copy("$base.pst",\*FILE); - } - # .ftr follows the footer to show "continue to next page" stuff - if( -f "$base.ftr" ) { - copy("$base.ftr",\*FILE); - } - else { - ++$num; - $base =~ s/[0-9]//g; - $next = sprintf("$base%02.2d",$num); - print FILE "<P><HR WIDTH=\"100%\">\n"; - print FILE "<CENTER>[<A HREF=\"..\">Tutorial Index</A>] "; - if( $file ne $ARGV[$#ARGV] ) { - print FILE "[<A HREF=\"$next.html\">Continue This Tutorial</A>]"; - } - print FILE "</CENTER>\n"; - } - close(FILE); -} - -sub addFile { - local($file) = @_; - - print FILE "<PRE>\n" ; - open(INPUT,"<$file") || die "Cannot open $file for read\n"; - # Do some substitutes on each line to try and get the output to - # look like it does in fontified emacs. - while( <INPUT> ) - { - s/</\</g; - s,\#(e?l?if !?defined|pragma|ifn?def|define)(\W*)([\w\.]+),<font color=blue>\#$1</font>$2<font color=purple>$3</font>,; - s,\#(include|endif),<font color=blue>$&</font>,; - s,"([^"]+)","<font color=green>$1</font>",g; - s,//.*$,<font color=red>$&</font>,; - s,/\*,<font color=red>$&,; - s,\*/,$&</font>,; - s,\w+::\~?\w+,<font color=\#008888>$&</font>,; - print FILE $_; - } - print FILE "</PRE>\n"; -} diff --git a/docs/tutorials/fix.Makefile b/docs/tutorials/fix.Makefile deleted file mode 100755 index 43557184492..00000000000 --- a/docs/tutorials/fix.Makefile +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/perl - -require "getopts.pl"; -&Getopts("f:o:"); - -$opt_f = "Makefile" if( ! $opt_f ); -$opt_o = ".depend" if( ! $opt_o ); - - # Open the Makefile that has been mangled by 'make depend' - # and suck it into a perl array. -open(IF,"<$opt_f") || die; -@makefile = <IF>; -close(IF); - - # Now open our .depend file and a temporary Makefile. - # We'll split the original Makefile between these two. -open(DF,">$opt_o") || die; -open(MF,">$opt_f.tmp") || die; - - # For each line we read out of the original file... -foreach (@makefile) { - - # If we're into the dependency section, write the line - # into the .depend file. - # - if( $depend ) { - print DF $_; - } - else { - # If we haven't gotten to the dependency section yet - # then see if the current line is the separator that - # "make depend" causes to be inserted. - # - if( m/^\Q# DO NOT DELETE THIS LINE -- g++dep uses it.\E/ ) { - - # If so, change our "mode" and skip this line. - ++$depend; - next; - } - - # Also skip the "include .depend" that we insert. If we - # don't do this, it is possible to have a bunch of these - # inserted into the output when we read an unmangled Makefile - next if( m/^include $opt_o/ ); - - # Print the non-dependency info to the temporary Makefile - print MF $_; - } -} - -# Tell our new Makefile to include the dependency file -print MF "include $opt_o\n"; - -# Close the two output files... -close(DF); -close(MF); - -# Unlink (remove) the original Makefile and rename our -# temporary file. There's obviously room for error checking -# here but we've got the Makefile checked into some revision -# control system anyway. Don't we? - -unlink("$opt_f"); -rename("$opt_f.tmp","$opt_f"); - -exit(0); diff --git a/docs/tutorials/index.html b/docs/tutorials/index.html deleted file mode 100644 index bbdd6e350e7..00000000000 --- a/docs/tutorials/index.html +++ /dev/null @@ -1,119 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <TITLE>Online ACE Tutorials</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<HR> -<H3> -Online ACE Tutorials</H3> - -The following online tutorials are designed to help get you started -with ACE. The original audience for these tutorials was the <A -HREF="http://www.lads.com">Automated Design Systems</A> (ADS) IPC -team, lead by <A HREF="mailto:jcej@lads.com">James Johnson</A>. Since -then, the scope has been changed to include anyone who wants to learn -about the ACE framework. Hopefully, even experienced ACE programmers -will find something new here. With a framework as encompassing as ACE, -it is easy to become an expert in one area and know little or nothing -about others. <P> - -<FONT size=-1>Before you try compiling Tutorial 2 (and beyond) you -might want to read these comments about <A HREF="templates.html">C++ -templates</A></font> <P> - -<P><HR WIDTH="50%" align=left><P> -<H4> -Your basic Client/Server hookup</H4> - -<OL> -<LI> -<A HREF="001/page01.html">A -Simple Server</A></LI> - -<LI> -<A HREF="002/page01.html">A -Simpler Server</A></LI> - -<LI> -<A HREF="003/page01.html">Finally, -a Client</A></LI> - -<LI> -<A HREF="004/page01.html">A -much <I>cooler</I> client</A></LI> -</OL> - -<P><HR WIDTH="50%" align=left><P> -<H4> -A word about concurrency</H4> - -<OL> -<LI> -<A HREF="005/page01.html">No -threads, nothing fancy, just do the work!</A></LI> - -<LI> -<A HREF="006/page01.html">I'd -like to dedicate... a thread to each connection.</A></LI> - -<LI> -<A HREF="007/page01.html">Let's -pool our resources: a fixed-size pool of threads.</A></LI> -</OL> - -<P><HR WIDTH="50%" align=left><P> -<H4> -Finding servers on your network</H4> - -<OL> -<LI> -<A HREF="008/page01.html">Calling -all servers!</A></LI> - -<LI> -<A HREF="009/page01.html">Discriminating tastes...</A></LI> -</OL> - -<P><HR WIDTH="50%" align=left><P> - -<H4> -A word about ACE_Message_Queue</H4> - -<OL> -<LI> -<A HREF="010/page01.html">Puttin' data</A></LI> -<LI> -<A HREF="011/page01.html">What about non-trivial data?</A></LI> -<LI> -<A HREF="012/page01.html">Puttin' pointers</A></LI> -<LI> -<A HREF="013/page01.html">Task chains and state machines</A></LI> -</OL> - -<P><HR WIDTH="50%" align=left><P> - -<H4> -Paddling down (and up) the ACE_Stream</H4> - -<OL> -<LI> -<A HREF="014/page01.html">ACE_Stream Tutorial, Of Sorts</A></LI> -<LI> -<A HREF="015/page01.html">A certain amount of Protocol is required!</A></LI> -</OL> - -<HR> - -<P>Back to the <A -HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/docs/ACE-tutorials.html">ACE -tutorials</A> page. - -<P> -<!--#include virtual="/~schmidt/cgi-sig.html" --> -</BODY> -</HTML> - diff --git a/docs/tutorials/linify b/docs/tutorials/linify deleted file mode 100755 index f44747f5269..00000000000 --- a/docs/tutorials/linify +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/local/bin/perl - -while( $#ARGV > -1 ) { - - print "$ARGV[0]\n"; - - $source = "$ARGV[0]"; - - if( $source =~ /~$/ ) { - $dest = "$`"; - } else { - rename("$source","$source"."~") || die "Cannot rename ($source)"; - $dest = "$source"; - $source .= "~"; - } - - open(INPUT,"<$source") || die "Cannot open ($source)"; - open(OUTPUT,">$dest") || die "Cannot open ($dest)"; - - $n = 1; - - $prestrip = 0; - while( <INPUT> ) { - chomp; - - if( ! $prestrip && /^[0-9]+\.\t/ ) { - $prestrip = 1; - $_ = $'; - } elsif( $prestrip ) { - if( /^[0-9]+\.\t/ ) { - $_ = $'; - } else { - s/^\t//; - } - } - - if( /^\s*$/ || /^\s*({|})\s*;?\s*$/ || /^\s*\/\// - || /^\s*private\s*:/ || /^\s*protected\s*:/ || /^\s*public\s*:/ - || /^\s*}?\s*else\s*{?\s*:/ - ) { - print OUTPUT "\t$_\n"; - } else { - print OUTPUT "$n.\t$_\n"; - ++$n; - } - } - - close(INPUT); - close(OUTPUT); - - shift(@ARGV); -} diff --git a/docs/tutorials/new-tutorials.html b/docs/tutorials/new-tutorials.html deleted file mode 100644 index a886f6f0094..00000000000 --- a/docs/tutorials/new-tutorials.html +++ /dev/null @@ -1,80 +0,0 @@ -<TITLE>ACE Beginners' Guide</TITLE> -<BODY text = "#000000" link="#000fff" vlink="#ff0f0f" bgcolor="#ffffff"> - -<HR><P> -<H3>Developing New Tutorials</H3> - -Here are some general guidelines for creating new ACE tutorials: <P> - -<hr width=50% align=left> -<H4>Choose a Topic You Know Very Well (or are just learning)</h4> - - This isn't really a conflict... -<P> - If you know a topic very well, you're likely to know what is most - important to the novice and what can be left until later. If you're - just learning a topic, then you know what questions you have that - must be answered before you can continue. -<P> -<hr width=50% align=left> -<H4> Keep It Simple</H4> -<P> - Don't try to use a lot of really cool ACE features along the way. Stick - to the basic stuff and show that. Try to use a minimum of ACE objects - that are not the direct target of the tutorial. -<P> - (For instance, don't get all caught up in ACE_Singleton<> if you're - trying to show how to use an ACE_Reactor.) -<P> - If you want to show something really cool that happens to depend on - another ACE feature, do a tutorial on that other feature first! I've - found that folks will tend to get stuck on *anything* they don't - understand even if it isn't directly relevant to what you're trying - to teach. -<P> -<hr width=50% align=left> -<h4>Document the Heck Out of It!</H4> -<P> - There's no such thing as too much documentation. Don't worry about - repeating yourself along the way. Assume that the reader knows nothing - at all about the topic at hand and explain even the parts that you feel - are painfully obvious. -<P> - If you feel that sticking a bunch of comments in the code makes it harder - to read then stick in a label and document at the end of the file or - something. Alternately, create both a well-documented version and a - sparsely-documented version. Then folks can choose between 'em. -<P> -<hr width=50% align=left> -<h4>Over-teach It</H4> -<P> - If there's a tutorial created for a topic that you feel strong in, - create another one anyway. Everybody tends to code a little differently. - Perhaps your tutorial style will "feel" better to some newcomers - than an existing tutorial. You won't hurt anybody's feelings if - you present the same material in a different way. -<P> -<hr width=50% align=left> -<h4>Leverage Existing Code</H4> -<P> - The ultimate form of code reuse :-) Seriously... grab one or more - of the existing ACE tests or examples. Then strip it down to the - bare bones & add heaps of comments. I don't think the software-police - will be coming after anyone for that! - -<P> If this thing takes off, I'll start to organize the tutorials into -groups. For now, lets concentrate on quantity & quality. -Organization can come later... <P> - -<HR><P> <H3> What about TAO?</H3> In the early stages, these tutorials -won't address The ACE ORB (<A -HREF="http://www.cs.wustl.edu/~schmidt">TAO</A>). However, if you -want to request a tutorial on some aspect of TAO or even create one -yourself, I'll be glad to integrate those into these tutorials. It's -rare when folks want to write documentation, so nothing will be -refused!<P> - -<HR><P> -Back to the <A -HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/docs/ACE-tutorials.html">ACE -tutorials</A> page. diff --git a/docs/tutorials/templates.html b/docs/tutorials/templates.html deleted file mode 100644 index 81294f489b0..00000000000 --- a/docs/tutorials/templates.html +++ /dev/null @@ -1,185 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> -<html> - <head> - <title>About C++ Templates</title> - </head> - - <BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> -<center> - <h1>About C++ Templates</h1> -</center> - - - <hr> - -When you get to server.cpp in Tutorial 2 you'll see these lines at the bottom: -<P> -<UL> -<PRE> -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ -<font size=-1>Thanks to Krishna Padmasola for providing these.</font> -</PRE> -</UL> -<P> -What's that all about? -<P> -Well, if you've been doing ACE for more than about 30 seconds you will -have run into the joys and sorrows of C++ templates. They're really -great things that prevent the need for complex #define'd macros, -ensure type safety and do other really nifty things. One of the -problems, however, is that not all compilers can figure out what -templates you need. -<P> -Take the simple templated class: -<UL> -<PRE> -template <class DATATYPE> -class MyTemplate -{ -public: - MyTemplate(void) - { - } - - DATATYPE data(void) - { - return data_; - } - - void data( DATATYE _data ) - { - data_ = _data; - } - -protected: - - DATATYPE data_; -}; -</PRE> -</UL> -<P> -Now suppose you write the following code fragment: -<P> -<UL> -<PRE> -int main(int,char**) -{ - MyTemplate<int> itemp; - MyTemplate<char> ctemp; - - ... -} -</pre> -</ul> -<P> -Some compilers will take care of you and automatically generate the -equivalent classes: -<UL> -<pre> -class MyTemplate -{ -public: - MyTemplate(void) - { - } - - int data(void) - { - return data_; - } - - void data( int _data ) - { - data_ = _data; - } - -protected: - - int data_; -}; - -class MyTemplate -{ -public: - MyTemplate(void) - { - } - - char data(void) - { - return data_; - } - - void data( char _data ) - { - data_ = _data; - } - -protected: - - char data_; -}; -</pre> -</ul> -<P> -On the other hand, some compilers will complain loudly about undefined -symbols and all sorts of other things. When Clinton Carr compiled -server.cpp of Tutorial 2 on his RedHat 5.1 (gcc) system, for instance, -he was rewarded with these lovely errors: -<P> -<UL> -<PRE> -server.cpp:60: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::ACE_Acceptor(ACE_Reactor *)' -server.cpp:72: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::open(ACE_INET_Addr const &, ACE_Reactor *,int)' -server.cpp:73: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::~ACE_Acceptor(void)' -server.cpp:112: undefined reference to `ACE_Acceptor<Client_Handler, ACE_SOCK_Acceptor>::~ACE_Acceptor(void)' -</PRE> -</UL> -<P> -Figuring out the correct manual instantiations is usually an -interative and tedious process. On Linux, I generally use a version of gcc that -will do automatic instantiaion. "Normal" gcc with the Cygnus repo -patches does that as does egcs. Lately (9/98) I've been using egcs -1.1b with pretty good results. On our Digital Unix 4.0b system the -native compiler (CXX) has switches that will request it to also -automatically instantiate templates as needed. -<P> -The tradeoffs? -<P> -If you choose to do manual instantiation then your code will work just -about anywhere ACE will. For complex applications, it can take a -number of hours to get things right. -<P> -If you choose to let the compiler do instantiations for you then it -will perform the iterative process. That means that every compile -will be longer than without manual instantiations. -<P> -Compromise? -<P> -Yes, you can do that. You can manually instantiate some -templates and let the compiler get the rest. Some compilers will -generate output that you can then use to figure out the correct -templates. Gcc/egcs create .rpo files for each object. These files -contain mangled names that the compiler uses to figure out what to -instantiate. With c++filt and some patience, you can parse that stuff -to figure out what the compiler is instantiating for you. -<P> -My best advice is to get a compiler that will handle the -instantiations for you. When you have some free time on your hands, -take a look at it's intermediate files (if any) and start working on -manual instantiation. -<P> -For some more hints, take a look at <A HREF="../../ACE-INSTALL.html#g++">ACE-INSTALL</A> -<P> - <hr> - - - </body> -</html> -
\ No newline at end of file |