diff options
author | nobody <nobody@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1998-09-03 02:14:37 +0000 |
---|---|---|
committer | nobody <nobody@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1998-09-03 02:14:37 +0000 |
commit | cc879558e7207ccb729a6d58adf99de0adb20479 (patch) | |
tree | 9894e7426f83f6e328a5997c5158eb61c0d6b1ff /docs/tutorials/006 | |
parent | b5c5bbde56430d3e45e88a0c0133be0071bfe33d (diff) | |
download | ATCD-TAO-0_2_8.tar.gz |
This commit was manufactured by cvs2svn to create tag 'TAO-0_2_8'.TAO-0_2_8
Diffstat (limited to 'docs/tutorials/006')
-rw-r--r-- | docs/tutorials/006/Makefile | 97 | ||||
-rw-r--r-- | docs/tutorials/006/client_acceptor.h | 81 | ||||
-rw-r--r-- | docs/tutorials/006/client_handler.cpp | 307 | ||||
-rw-r--r-- | docs/tutorials/006/client_handler.h | 120 | ||||
-rw-r--r-- | docs/tutorials/006/fix.Makefile | 60 | ||||
-rw-r--r-- | docs/tutorials/006/notify.cpp | 199 | ||||
-rw-r--r-- | docs/tutorials/006/page01.html | 33 | ||||
-rw-r--r-- | docs/tutorials/006/page02.html | 205 | ||||
-rw-r--r-- | docs/tutorials/006/page03.html | 167 | ||||
-rw-r--r-- | docs/tutorials/006/page04.html | 223 | ||||
-rw-r--r-- | docs/tutorials/006/page05.html | 503 | ||||
-rw-r--r-- | docs/tutorials/006/page06.html | 52 | ||||
-rw-r--r-- | docs/tutorials/006/server.cpp | 112 |
13 files changed, 0 insertions, 2159 deletions
diff --git a/docs/tutorials/006/Makefile b/docs/tutorials/006/Makefile deleted file mode 100644 index 999b85ce3c6..00000000000 --- a/docs/tutorials/006/Makefile +++ /dev/null @@ -1,97 +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.lib.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 - -#---------------------------------------------------------------------------- -# 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 b0944f3a316..00000000000 --- a/docs/tutorials/006/client_acceptor.h +++ /dev/null @@ -1,81 +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" - -/* - 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 cc2e302cde7..00000000000 --- a/docs/tutorials/006/client_handler.cpp +++ /dev/null @@ -1,307 +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) -{ - 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. - */ -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]; - 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... - 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 18bd6222a6b..00000000000 --- a/docs/tutorials/006/client_handler.h +++ /dev/null @@ -1,120 +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" -#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: - - // 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/notify.cpp b/docs/tutorials/006/notify.cpp deleted file mode 100644 index d38fe8868b0..00000000000 --- a/docs/tutorials/006/notify.cpp +++ /dev/null @@ -1,199 +0,0 @@ -// $Id$ - -#include "ace/Reactor.h" -#include "ace/Thread.h" -#include "ace/Message_Queue.h" - -typedef ACE_Message_Queue<ACE_MT_SYNCH> Message_Queue; - -//////////////////////////////////////////////////////////////////////////////// - -class IPCQueue : public Message_Queue -{ -protected: - ACE_Event_Handler * event_handler_; - ACE_Reactor * reactor_; -public: - IPCQueue( ) - { - event_handler_ = NULL; - reactor_ = NULL; - } - - void configure( ACE_Reactor * reactor, ACE_Event_Handler * handler ) - { - reactor_ = reactor; - event_handler_ = handler; - } - - virtual int notify(void) - { - if( reactor_ && event_handler_ ) - this->reactor_->notify( event_handler_, ACE_Event_Handler::WRITE_MASK); - - return 0; - } - - int dequeue( ACE_Message_Block * & message_block ) - { - ACE_Time_Value timeout(ACE_OS::time(0)+1,0); - - return dequeue_head(message_block,&timeout) ; - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -class FoobarBase -{ -protected: - IPCQueue data_queue_; - ACE_Thread_Manager & thr_mgr_; - -public: - FoobarBase( ACE_Thread_Manager & _thr_mgr ) : data_queue_ (), thr_mgr_ (_thr_mgr) - { - } - - ACE_Thread_Manager & thr_mgr(void) - { - return thr_mgr_; - } - - IPCQueue & queue() - { - return data_queue_; - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -class Foobar : public FoobarBase -{ -public: - Foobar( ACE_Thread_Manager & _thr_mgr ) : FoobarBase(_thr_mgr) - { - } - - void produce_data( char * buf ) - { - ACE_Message_Block *message_block = - new ACE_Message_Block( strlen(buf), ACE_Message_Block::MB_DATA, 0, buf ); - - data_queue_.enqueue_tail(message_block); - - return; - } - - void consume_data( char * buf ) - { - - if( buf ) - cerr << ACE_Thread::self() << " Consuming (" << buf << ") " << (void *)buf << endl; - - return; - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -template <class OBJ> -class FoobarHandler : public ACE_Event_Handler -{ -protected: - OBJ * foobar_; - -public: - FoobarHandler(OBJ * _foobar, ACE_Reactor * reactor) - { - foobar_ = _foobar; - - reactor->register_handler( this, ACE_Event_Handler::READ_MASK ); - this->reactor(reactor); - - foobar_->queue().configure( reactor, this ); - } - - virtual int handle_timeout (const ACE_Time_Value & tv, const void *arg = 0) - { - cerr << ACE_Thread::self() << " Timeout" << endl; - - this->reactor()->notify( this, ACE_Event_Handler::WRITE_MASK); - - return 0; - } - - virtual int handle_output (ACE_HANDLE) - { - ACE_Message_Block * block = NULL; - - if( foobar_->queue().dequeue(block) != -1 ) - { - foobar_->consume_data( block->base() ); - delete block; - } - else - { - cerr << ACE_Thread::self() << " Nothing in queue" << endl; - } - - return 0; - } -}; - -//////////////////////////////////////////////////////////////////////////////// - -static void *thread_func(void * arg1) -{ - Foobar * foobar = (Foobar *)arg1; - - ACE_Thread_Control thread_control ( & foobar->thr_mgr() ); - - ACE_Reactor reactor; - - FoobarHandler<Foobar> handler(foobar,&reactor); - - if (reactor.schedule_timer (&handler, 0, ACE_Time_Value (1, 0), ACE_Time_Value (0, 3500000)) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "ACE_Reactor::schedule_timer"), -1); - - for( int i = 0 ; i < 50 ; ++i ) - { - cerr << ACE_Thread::self() << " " << i << endl; - reactor.handle_events( ACE_Time_Value(5,0 ) ); - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// - -main() -{ - ACE_Thread_Manager thr_mgr; - - cerr << ACE_Thread::self() << " Main Thread" << endl; - - Foobar foobar(thr_mgr); - - if (thr_mgr.spawn(ACE_THR_FUNC (thread_func),&foobar,THR_NEW_LWP | THR_DETACHED) == -1) - ACE_ERROR_RETURN((LM_ERROR,"%p\n","spawing client thread"),1); - - sleep(1); - - for( int i = 0 ; i < 10 ; ++i ) - { - char buf[64]; - sprintf(buf,"This is iteration %d",i); - - foobar.produce_data(buf); - - sleep(2); - } - - thr_mgr.wait(); - - 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 2b79e79c7b9..00000000000 --- a/docs/tutorials/006/page05.html +++ /dev/null @@ -1,503 +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.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><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 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><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 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><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 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><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><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"> 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 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><FONT FACE="Arial,Helvetica"></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><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"> 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"> 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> -<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"> 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><FONT FACE="Arial,Helvetica"></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><FONT FACE="Arial,Helvetica"></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><FONT FACE="Arial,Helvetica"></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><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"> 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> - -<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 d0a1e0f42b3..00000000000 --- a/docs/tutorials/006/server.cpp +++ /dev/null @@ -1,112 +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; -} |