diff options
Diffstat (limited to 'docs/tutorials/005')
-rw-r--r-- | docs/tutorials/005/005.dsp | 112 | ||||
-rw-r--r-- | docs/tutorials/005/00SetEnv | 2 | ||||
-rw-r--r-- | docs/tutorials/005/Makefile | 118 | ||||
-rw-r--r-- | docs/tutorials/005/client_acceptor.h | 36 | ||||
-rw-r--r-- | docs/tutorials/005/client_handler.cpp | 221 | ||||
-rw-r--r-- | docs/tutorials/005/client_handler.h | 100 | ||||
-rw-r--r-- | docs/tutorials/005/combine.shar | 423 | ||||
-rw-r--r-- | docs/tutorials/005/page01.html | 33 | ||||
-rw-r--r-- | docs/tutorials/005/page02.html | 148 | ||||
-rw-r--r-- | docs/tutorials/005/page03.html | 71 | ||||
-rw-r--r-- | docs/tutorials/005/page04.html | 133 | ||||
-rw-r--r-- | docs/tutorials/005/page05.html | 249 | ||||
-rw-r--r-- | docs/tutorials/005/page06.html | 144 | ||||
-rw-r--r-- | docs/tutorials/005/page07.html | 95 | ||||
-rw-r--r-- | docs/tutorials/005/page08.html | 47 | ||||
-rw-r--r-- | docs/tutorials/005/server.brk | 154 | ||||
-rw-r--r-- | docs/tutorials/005/server.cpp | 111 |
17 files changed, 0 insertions, 2197 deletions
diff --git a/docs/tutorials/005/005.dsp b/docs/tutorials/005/005.dsp deleted file mode 100644 index 024b1aef6b7..00000000000 --- a/docs/tutorials/005/005.dsp +++ /dev/null @@ -1,112 +0,0 @@ -# Microsoft Developer Studio Project File - Name="005" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=005 - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "005.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "005.mak" CFG="005 - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "005 - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "005 - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "005 - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\.." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 ace.lib /nologo /subsystem:console /machine:I386 /libpath:"..\..\..\ace"
-
-!ELSEIF "$(CFG)" == "005 - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MDd /W3 /GX /Od /I "..\..\.." /D "WIN32" /D "_DEBUG" /YX /FD /c
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 aced.lib /nologo /subsystem:console /debug /machine:I386 /out:"client.exe" /pdbtype:sept /libpath:"..\..\..\ace"
-
-!ENDIF
-
-# Begin Target
-
-# Name "005 - Win32 Release"
-# Name "005 - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\client_handler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\server.cpp
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\client_acceptor.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\client_handler.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
diff --git a/docs/tutorials/005/00SetEnv b/docs/tutorials/005/00SetEnv deleted file mode 100644 index eca78e10c85..00000000000 --- a/docs/tutorials/005/00SetEnv +++ /dev/null @@ -1,2 +0,0 @@ -export ACE_ROOT=/local/src/ACE/ACE_wrappers -export LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH diff --git a/docs/tutorials/005/Makefile b/docs/tutorials/005/Makefile deleted file mode 100644 index d8f01d76929..00000000000 --- a/docs/tutorials/005/Makefile +++ /dev/null @@ -1,118 +0,0 @@ -#---------------------------------------------------------------------------- -# $Id$ -#---------------------------------------------------------------------------- - -#---------------------------------------------------------------------------- -# Local macros -#---------------------------------------------------------------------------- - -# You can generally find a Makefile in the ACE examples, tests or the library -# itself that will satisfy our application needs. This one was taken from -# one of the examples. - - # Define the name of the binary we want to create. There has to be - # a CPP file $(BIN).cpp but it doesn't necessarily have to have your - # main() in it. Most of the time, though, it will. -BIN = server - - # Few applications will have a single source file. We use the FILES - # macro to build up a list of additional files to compile. Notice - # that we leave off the extension just as with BIN -FILES = -FILES += client_handler - - # The BUILD macro is used by the ACE makefiles. Basically, it tells - # the system what to build. I don't really know what VBIN is other - # than it is constructed from the value of BIN. Just go with it... -BUILD = $(VBIN) - - # Here we use some GNU make extensions to build the SRC macro. Basically, - # we're just adding .cpp to the value of BIN and for each entry of the - # FILES macro. -SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES)) - - # This is used by my Indent target below. It's not a part of standard - # ACE and you don't need it yourself. -HDR = *.h - -#---------------------------------------------------------------------------- -# Include macros and targets -#---------------------------------------------------------------------------- - - # This is where the real power lies! These included makefile components - # are similar to the C++ templates in ACE. That is, they do a tremendous - # amount of work for you and all you have to do is include them. - # As a matter of fact, in our project, I created a single file named - # "app.mk" that includes all of these. Our project makefiles then just - # need to include app.mk to get everything they need. - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - - # Sometimes I like to reformat my code to make it more readable. This is - # more useful for the comments than anything else. Unfortunately, the - # "indent" program doesn't quite grok C++ so I have to post-process it's - # output just a bit. -Indent : # - for i in $(SRC) $(HDR) ; do \ - indent -npsl -l80 -fca -fc1 -cli0 -cdb < $$i | \ - sed -e 's/: :/::/g' \ - -e 's/^.*\(public:\)/\1/' \ - -e 's/^.*\(protected:\)/\1/' \ - -e 's/^.*\(private:\)/\1/' \ - -e 's/:\(public\)/ : \1/' \ - -e 's/:\(protected\)/ : \1/' \ - -e 's/:\(private\)/ : \1/' \ - > $$i~ ;\ - mv $$i~ $$i ;\ - done - - # One of the targets in the ACE makefiles is "depend". It will invoke - # your compiler in a way that will generate a list of dependencies for - # you. This is a great thing! Unfortunately, it puts all of that mess - # directly into the Makefile. I prefer my Makefile to stay clean and - # uncluttered. The perl script referenced here pulls the dependency - # stuff back out of the Makefile and into a file ".depend" which we then - # include just like the makefile components above. - # - # NOTE: The 'depend' target expects to have GCC available. - # You can do the same thing with other compilers but the ACE - # makefiles and utilities are only wired up to work with GCC. -Depend : depend - perl ../fix.Makefile - -.depend : # - touch .depend - - -HTML : # - [ -f hdr ] || $(MAKE) UNSHAR - perl ../combine *.pre ; chmod +r *.html - -SHAR : # - [ ! -f combine.shar ] || exit 1 - shar -T hdr bodies *.pre > combine.shar && $(RM) hdr bodies *.pre *.pst - -UNSHAR : # - sh combine.shar - -CLEAN : realclean - $(RM) hdr bodies *.pre *.pst .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - - # Don't put anything below here. Between the "depend" target and fix.Makefile - # it's guaranteed to be lost! - - # This is inserted by the fix.Makefile script -include .depend diff --git a/docs/tutorials/005/client_acceptor.h b/docs/tutorials/005/client_acceptor.h deleted file mode 100644 index 44db0e9984b..00000000000 --- a/docs/tutorials/005/client_acceptor.h +++ /dev/null @@ -1,36 +0,0 @@ -// $Id$ - -#ifndef CLIENT_ACCEPTOR_H -#define CLIENT_ACCEPTOR_H - -/* The ACE_Acceptor<> template lives in the ace/Acceptor.h header - file. You'll find a very consitent naming convention between the - ACE objects and the headers where they can be found. In general, - the ACE object ACE_Foobar will be found in ace/Foobar.h. */ - -#include "ace/Acceptor.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -/* Since we want to work with sockets, we'll need a SOCK_Acceptor to - allow the clients to connect to us. */ -#include "ace/SOCK_Acceptor.h" - -/* The Client_Handler object we develop will be used to handle clients - once they're connected. The ACE_Acceptor<> template's first - parameter requires such an object. In some cases, you can get by - with just a forward declaration on the class, in others you have to - have the whole thing. */ -#include "client_handler.h" - -/* Parameterize the ACE_Acceptor<> such that it will listen for socket - connection attempts and create Client_Handler objects when they - happen. In Tutorial 001, we wrote the basic acceptor logic on our - own before we realized that ACE_Acceptor<> was available. You'll - get spoiled using the ACE templates because they take away a lot of - the tedious details! */ -typedef ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR> Client_Acceptor; - -#endif /* CLIENT_ACCEPTOR_H */ diff --git a/docs/tutorials/005/client_handler.cpp b/docs/tutorials/005/client_handler.cpp deleted file mode 100644 index 8466992b6a0..00000000000 --- a/docs/tutorials/005/client_handler.cpp +++ /dev/null @@ -1,221 +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) -{ - // Make sure that our peer closes when we're deleted. This - // will probably happened when the peer is deleted but it - // doesn't hurt to be explicit. - this->peer ().close (); -} - -/* 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) -{ - /* Tell the reactor to forget all about us. Notice that we use the - same args here that we use in the open() method to register - ourselves. In addition, we use the DONT_CALL flag to prevent - handle_close() being called. Since we likely got here due to - handle_close(), that could cause a bit of nasty recursion! */ - this->reactor ()->remove_handler (this, - ACE_Event_Handler:: READ_MASK | ACE_Event_Handler::DONT_CALL); - - /* This is how we're able to tell folks not to use delete. By - deleting our own instance, we take care of memory leaks after - ensuring that the object is shut down correctly. */ - delete this; -} - -/* As mentioned before, the open() method is called by the - Client_Acceptor when a new client connection has been accepted. - The Client_Acceptor instance pointer is cast to a void* and given - to us here. We'll use that to avoid some global data... */ -int -Client_Handler::open (void *_acceptor) -{ - /* Convert the void* to a Client_Acceptor*. You should probably use - those fancy ACE_*_cast macros but I can never remember how/when - to do so. Since you can cast just about anything around a void* - without compiler warnings be very sure of what you're doing when - you do this kind of thing. That's where the new-style cast - operators can save you. */ - Client_Acceptor *acceptor = (Client_Acceptor *) _acceptor; - - /* Our reactor reference will be set when we register ourselves but - I decided to go ahead and set it here. No good reason really... */ - this->reactor (acceptor->reactor ()); - - /* We need this to store the address of the client that we are now - connected to. We'll use it later to display a debug message. */ - ACE_INET_Addr addr; - - /* Our ACE_Svc_Handler baseclass gives us the peer() method as a way - to access our underlying ACE_SOCK_Stream. On that object, we can - invoke the get_remote_addr() method to get an ACE_INET_Addr - having our client's address information. As with most ACE - methods, we'll get back (and return) a -1 if there was any kind - of error. Once we have the ACE_INET_Addr, we can query it to - find out the clien's host name, TCP/IP address, TCP/IP port value - and so forth. One word of warning: the get_host_name() method of - ACE_INET_Addr may return you an empty string if your name server - can't resolve it. On the other hand, get_host_addr() will always - give you the dotted-decimal string representing the TCP/IP - address. */ - if (this->peer ().get_remote_addr (addr) == -1) - return -1; - - /* If we managed to get the client's address then we're connected to - a real and valid client. I suppose that in some cases, the - client may connect and disconnect so quickly that it is invalid - by the time we get here. In any case, the test above should - always be done to ensure that the connection is worth keeping. - - Now, register ourselves with a reactor and tell that reactor that - we want to be notified when there is something to read. - Remember, we took our reactor value from the acceptor which - created us in the first place. Since we're exploring a - single-threaded implementation, this is the correct thing to do. */ - if (this->reactor ()->register_handler (this, - ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR, - "(%P|%t) can't register with reactor\n"), - -1); - - /* Here, we use the ACE_INET_Addr object to print a message with the - name of the client we're connected to. Again, it is possible - that you'll get an empty string for the host name if your DNS - isn't configured correctly or if there is some other reason that - a TCP/IP addreess cannot be converted into a host name. */ - ACE_DEBUG ((LM_DEBUG, - "(%P|%t) connected with %s\n", - addr.get_host_name ())); - - /* Always return zero on success. */ - return 0; -} - -/* In the open() method, we registered with the reactor and requested - to be notified when there is data to be read. When the reactor - sees that activity it will invoke this handle_input() method on us. - As I mentioned, the _handle parameter isn't useful to us but it - narrows the list of methods the reactor has to worry about and the - list of possible virtual functions we would have to override. */ -int -Client_Handler::handle_input (ACE_HANDLE handle) -{ - /* Some compilers don't like it when you fail to use a parameter. - This macro will keep 'em quiet for you. */ - ACE_UNUSED_ARG (handle); - - /* Now, we create and initialize a buffer for receiving the data. - Since this is just a simple test app, we'll use a small buffer - size. */ - char buf[BUFSIZ]; - - /* 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. The reactor - framework will take care of removing us (due to the -1), so we - don't need to use the destroy() method. Instead, we just delete - ourselves directly. */ -int -Client_Handler::handle_close (ACE_HANDLE handle, - ACE_Reactor_Mask mask) -{ - ACE_UNUSED_ARG (handle); - ACE_UNUSED_ARG (mask); - - delete this; - 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: // Complain and leave - ACE_ERROR_RETURN ((LM_ERROR, - "(%P|%t) %p bad read\n", - "client"), - -1); - case 0: // Complain and leave - ACE_ERROR_RETURN ((LM_ERROR, - "(%P|%t) closing daemon (fd = %d)\n", - this->get_handle ()), - -1); - default: // Show the data - ACE_DEBUG ((LM_DEBUG, - "(%P|%t) from client: %s", - rdbuf)); - } - - /* It's also worth mentioning that recv() has a cousin: recv_n(). - recv_n() will receive exactly the number of bytes you provide it. - This is very good when you know exactly how much you expect to - receive. For the application here, unfortunately, we don't have - any idea how much the client will be sending. recv() will read - up-to-but-not-more-than the number of bytes we specify (e.g. -- - _rdbuf_len). That works well when we don't know how much the - client will provide. */ - - return 0; -} diff --git a/docs/tutorials/005/client_handler.h b/docs/tutorials/005/client_handler.h deleted file mode 100644 index 4a579110a6b..00000000000 --- a/docs/tutorials/005/client_handler.h +++ /dev/null @@ -1,100 +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 actual connection. With a direct derivative of - ACE_Event_Handler, you'll have to contain and maintain an - ACE_SOCK_Stream instance yourself. With ACE_Svc_Handler (which is - a derivative of ACE_Event_Handler) some of those details are - handled for you. */ - -#include "ace/Svc_Handler.h" - -#if !defined (ACE_LACKS_PRAGMA_ONCE) -# pragma once -#endif /* ACE_LACKS_PRAGMA_ONCE */ - -#include "ace/SOCK_Stream.h" - -/* Another feature of ACE_Svc_Handler is it's ability to present the - ACE_Task<> interface as well. That's what the ACE_NULL_SYNCH - parameter below is all about. That's beyond our scope here but - we'll come back to it in the next tutorial when we start looking at - concurrency options. */ -class Client_Handler : public ACE_Svc_Handler <ACE_SOCK_STREAM, ACE_NULL_SYNCH> -{ -public: - // Constructor... - Client_Handler (void); - - /* The destroy() method is our preferred method of destruction. We - could have overloaded the delete operator but that is neither easy - nor intuitive (at least to me). Instead, we provide a new method - of destruction and we make our destructor protected so that only - ourselves, our derivatives and our friends can delete us. It's a - nice compromise. */ - void destroy (void); - - /* Most ACE objects have an open() method. That's how you make them - ready to do work. ACE_Event_Handler has a virtual open() method - which allows us to create an override. ACE_Acceptor<> will invoke - this method after creating a new Client_Handler when a client - connects. Notice that the parameter to open() is a void*. It just - so happens that the pointer points to the acceptor which created - us. You would like for the parameter to be an ACE_Acceptor<>* but - since ACE_Event_Handler is generic, that would tie it too closely - to the ACE_Acceptor<> set of objects. In our definition of open() - you'll see how we get around that. */ - int open (void *acceptor); - - /* When there is activity on a registered handler, the - handle_input() method of the handler will be invoked. If that - method returns an error code (eg -- -1) then the reactor will - invoke handle_close() to allow the object to clean itself - up. Since an event handler can be registered for more than one - type of callback, the callback mask is provided to inform - handle_close() exactly which method failed. That way, you don't - have to maintain state information between your handle_* method - calls. The <handle> parameter is explained below... As a - side-effect, the reactor will also invoke remove_handler() for the - object on the mask that caused the -1 return. This means that we - don't have to do that ourselves! */ - int handle_close (ACE_HANDLE handle, - ACE_Reactor_Mask mask); - -protected: - - /* When we register with the reactor, we're going to tell it that we - want to be notified of READ events. When the reactor sees that - there is read activity for us, our handle_input() will be - invoked. The _handle 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 its 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 <handle> would - be important to us for reading the client's data. */ - int handle_input (ACE_HANDLE handle); - - /* This has nothing at all to do with ACE. I've added this here as - a worker function which I will call from handle_input(). That - allows me to introduce concurrency in later tutorials with no - changes to the worker function. You can think of process() as - application-level code and everything else as - application-framework code. */ - int process (char *rdbuf, int rdbuf_len); - - /* We don't really do anything in our destructor but we've declared - it to be protected to prevent casual deletion of this object. As - I said above, I really would prefer that everyone goes through the - destroy() method to get rid of us. */ - ~Client_Handler (void); -}; - -#endif /* CLIENT_HANDLER_H */ diff --git a/docs/tutorials/005/combine.shar b/docs/tutorials/005/combine.shar deleted file mode 100644 index 28175d7785e..00000000000 --- a/docs/tutorials/005/combine.shar +++ /dev/null @@ -1,423 +0,0 @@ -#!/bin/sh -# This is a shell archive (produced by GNU sharutils 4.2). -# To extract the files from this archive, save it to some FILE, remove -# everything before the `!/bin/sh' line above, then type `sh FILE'. -# -# Made on 1999-01-24 14:30 EST by <jcej@chiroptera.tragus.org>. -# Source directory was `/var/home/jcej/projects/ACE_wrappers/docs/tutorials/005'. -# -# Existing files will *not* be overwritten unless `-c' is specified. -# -# This shar contains: -# length mode name -# ------ ---------- ------------------------------------------ -# 598 -rw-rw-r-- hdr -# 97 -rw-rw-r-- bodies -# 628 -rw-rw-r-- page01.pre -# 516 -rw-rw-r-- page02.pre -# 685 -rw-rw-r-- page03.pre -# 464 -rw-rw-r-- page04.pre -# 218 -rw-rw-r-- page05.pre -# 98 -rw-rw-r-- page06.pre -# 172 -rw-rw-r-- page07.pre -# 715 -rw-rw-r-- page08.pre -# -save_IFS="${IFS}" -IFS="${IFS}:" -gettext_dir=FAILED -locale_dir=FAILED -first_param="$1" -for dir in $PATH -do - if test "$gettext_dir" = FAILED && test -f $dir/gettext \ - && ($dir/gettext --version >/dev/null 2>&1) - then - set `$dir/gettext --version 2>&1` - if test "$3" = GNU - then - gettext_dir=$dir - fi - fi - if test "$locale_dir" = FAILED && test -f $dir/shar \ - && ($dir/shar --print-text-domain-dir >/dev/null 2>&1) - then - locale_dir=`$dir/shar --print-text-domain-dir` - fi -done -IFS="$save_IFS" -if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED -then - echo=echo -else - TEXTDOMAINDIR=$locale_dir - export TEXTDOMAINDIR - TEXTDOMAIN=sharutils - export TEXTDOMAIN - echo="$gettext_dir/gettext -s" -fi -touch -am 1231235999 $$.touch >/dev/null 2>&1 -if test ! -f 1231235999 && test -f $$.touch; then - shar_touch=touch -else - shar_touch=: - echo - $echo 'WARNING: not restoring timestamps. Consider getting and' - $echo "installing GNU \`touch', distributed in GNU File Utilities..." - echo -fi -rm -f 1231235999 $$.touch -# -if mkdir _sh22890; then - $echo 'x -' 'creating lock directory' -else - $echo 'failed to create lock directory' - exit 1 -fi -# ============= hdr ============== -if test -f 'hdr' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'hdr' '(file already exists)' -else - $echo 'x -' extracting 'hdr' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'hdr' && -<HTML> -<HEAD> -X <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> -X <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> -X <META NAME="Author" CONTENT="Billy Quinn"> -X <META NAME="Description" CONTENT="A first step towards using ACE productively"> -X <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> -X -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> -X -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> -X -X -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 0117143899 'hdr' && - chmod 0664 'hdr' || - $echo 'restore of' 'hdr' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'hdr:' 'MD5 check failed' -197a3d789965f9c046d4d84ee137ace9 hdr -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'hdr'`" - test 598 -eq "$shar_count" || - $echo 'hdr:' 'original size' '598,' 'current size' "$shar_count!" - fi -fi -# ============= bodies ============== -if test -f 'bodies' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'bodies' '(file already exists)' -else - $echo 'x -' extracting 'bodies' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'bodies' && -PAGE=2 -server.cpp -client_acceptor.h -client_handler.h -client_handler.cpp -Makefile -X../fix.Makefile -SHAR_EOF - $shar_touch -am 0117143799 'bodies' && - chmod 0664 'bodies' || - $echo 'restore of' 'bodies' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'bodies:' 'MD5 check failed' -dcbb8d7d85345e022a122f4f7fa10fb9 bodies -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'bodies'`" - test 97 -eq "$shar_count" || - $echo 'bodies:' 'original size' '97,' 'current size' "$shar_count!" - fi -fi -# ============= page01.pre ============== -if test -f 'page01.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page01.pre' '(file already exists)' -else - $echo 'x -' extracting 'page01.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page01.pre' && -X -<P>In this tutorial, we're going to flash-back to the simple server we -created a while back. We'll create a very simple server where everything -takes place in one thread. Once we have a solid understanding there, -we'll move on to the next tutorial where we begin to introduce concurrency -concepts. -X -<P>There are four C++ source files in this tutorial: server.cpp, -client_acceptor.h, client_handler.h and client_handler.cpp. I'll -talk about each of these in turn with the usual color commentary as we -go. In addition, I'll briefly discuss the Makefile and a short perl -script I've added. -X -<P> -SHAR_EOF - $shar_touch -am 0117143899 'page01.pre' && - chmod 0664 'page01.pre' || - $echo 'restore of' 'page01.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page01.pre:' 'MD5 check failed' -b819665dcbed1ef2efe12bdc8d8710c5 page01.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page01.pre'`" - test 628 -eq "$shar_count" || - $echo 'page01.pre:' 'original size' '628,' 'current size' "$shar_count!" - fi -fi -# ============= page02.pre ============== -if test -f 'page02.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page02.pre' '(file already exists)' -else - $echo 'x -' extracting 'page02.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page02.pre' && -X -<P>We begin with <I><A HREF="server.cpp">server.cpp</A></I>. -<P> -Abstraction by Kirthika: -<UL> -This tutorial is a re-cap of the client-server hookup tutorial with much -X cleaner code (for instance: use of destroy() to delete objects and -process() which does the task of reading in data from the client). -<P> -We again enroll the services of the ACE_Reactor to handle events. Everything -occurs in a single thread. -<P> -This tutorial is a stepping stone towards a mutithreaded server model. -</ul> -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 0124115599 'page02.pre' && - chmod 0664 'page02.pre' || - $echo 'restore of' 'page02.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page02.pre:' 'MD5 check failed' -c81f5251d4ec6de954b9d2f5a026525b page02.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page02.pre'`" - test 516 -eq "$shar_count" || - $echo 'page02.pre:' 'original size' '516,' 'current size' "$shar_count!" - fi -fi -# ============= page03.pre ============== -if test -f 'page03.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page03.pre' '(file already exists)' -else - $echo 'x -' extracting 'page03.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page03.pre' && -X -<P>Now, let's take a look at <I><A HREF="client_acceptor.h">client_acceptor.h</A></I>. -Since I went on about how it does all the work of letting clients connect -to us, it must be rather complex. Right? Wrong. -X -<P>The more you use ACE, the more you'll find that they've already taken -care of most details for you. With respect to the acceptance of client -connections: there just aren't that many ways to do it! The -ACE team has chosen an approach and created a C++ template that does -all of the work for you. All you're required to do is provide it -with an object type to instantiate when a new connection arrives. -X -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 0124115699 'page03.pre' && - chmod 0664 'page03.pre' || - $echo 'restore of' 'page03.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page03.pre:' 'MD5 check failed' -edb44ba6e3033259e60b4a83d0675b03 page03.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page03.pre'`" - test 685 -eq "$shar_count" || - $echo 'page03.pre:' 'original size' '685,' 'current size' "$shar_count!" - fi -fi -# ============= page04.pre ============== -if test -f 'page04.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page04.pre' '(file already exists)' -else - $echo 'x -' extracting 'page04.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page04.pre' && -X -<P>Ok, so we've got a main() loop that sets up the acceptor and we've seen -how easy it is to create the acceptor object. So far, we've hardly -written any code at all. Well, that's just about to change... -X -<P>First, we look at <I><A HREF="client_handler.h">client_handler.h</A></I> -for the declaration of the Client_Handler object. Then we look at -the definition where all of the real work of the application takes place. -X -<P> -<HR WIDTH="100%"> -X -SHAR_EOF - $shar_touch -am 0117143899 'page04.pre' && - chmod 0664 'page04.pre' || - $echo 'restore of' 'page04.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page04.pre:' 'MD5 check failed' -3a0e0d0c79318ca18dd5920dd97ca834 page04.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page04.pre'`" - test 464 -eq "$shar_count" || - $echo 'page04.pre:' 'original size' '464,' 'current size' "$shar_count!" - fi -fi -# ============= page05.pre ============== -if test -f 'page05.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page05.pre' '(file already exists)' -else - $echo 'x -' extracting 'page05.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page05.pre' && -X -<P>Now we're finally at <I><A HREF="client_handler.cpp">client_handler.cpp</A></I> -where we have to write some code. This file has more code than the -rest of the application all together. -X -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 0117143899 'page05.pre' && - chmod 0664 'page05.pre' || - $echo 'restore of' 'page05.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page05.pre:' 'MD5 check failed' -d5fa96547c3b94abc387c8b87f2f3c92 page05.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page05.pre'`" - test 218 -eq "$shar_count" || - $echo 'page05.pre:' 'original size' '218,' 'current size' "$shar_count!" - fi -fi -# ============= page06.pre ============== -if test -f 'page06.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page06.pre' '(file already exists)' -else - $echo 'x -' extracting 'page06.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page06.pre' && -X -<P>Before we go, I wanted you to see the <A HREF="Makefile">Makefile</A>. -X -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 0117143899 'page06.pre' && - chmod 0664 'page06.pre' || - $echo 'restore of' 'page06.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page06.pre:' 'MD5 check failed' -b8a35eb354a8e5c90155dd728a8bfa4e page06.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page06.pre'`" - test 98 -eq "$shar_count" || - $echo 'page06.pre:' 'original size' '98,' 'current size' "$shar_count!" - fi -fi -# ============= page07.pre ============== -if test -f 'page07.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page07.pre' '(file already exists)' -else - $echo 'x -' extracting 'page07.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page07.pre' && -X -<P>And last (and probably least) is the <A HREF="../fix.Makefile">perl script</A> -that pulls the dependency stuff out of Makefile and into .depend. -X -<P> -<HR WIDTH="100%"> -SHAR_EOF - $shar_touch -am 0117144099 'page07.pre' && - chmod 0664 'page07.pre' || - $echo 'restore of' 'page07.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page07.pre:' 'MD5 check failed' -7f896dc992a365d4d095d0a6d3b9eb47 page07.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page07.pre'`" - test 172 -eq "$shar_count" || - $echo 'page07.pre:' 'original size' '172,' 'current size' "$shar_count!" - fi -fi -# ============= page08.pre ============== -if test -f 'page08.pre' && test "$first_param" != -c; then - $echo 'x -' SKIPPING 'page08.pre' '(file already exists)' -else - $echo 'x -' extracting 'page08.pre' '(text)' - sed 's/^X//' << 'SHAR_EOF' > 'page08.pre' && -X -<P>That's it for Tutorial 5. In this tutorial we've built a single-threaded -reactor-based server. We've done a couple of things that aren't exactly -necessary for such an implementation but I plan to build on that as -we explore two other concurrency strategies: thread per connection -and thread pool. -X -<P>For reference, here's the file list again: -<UL> -<LI> -<A HREF="Makefile">Makefile</A></LI> -X -<LI> -<A HREF="client_acceptor.h">client_acceptor.h</A></LI> -X -<LI> -<A HREF="client_handler.cpp">client_handler.cpp</A></LI> -X -<LI> -<A HREF="client_handler.h">client_handler.h</A></LI> -X -<LI> -<A HREF="server.cpp">server.cpp</A></LI> -X -<LI> -<A HREF="../fix.Makefile">fix.Makefile</A></LI> -</UL> - -SHAR_EOF - $shar_touch -am 0117143899 'page08.pre' && - chmod 0664 'page08.pre' || - $echo 'restore of' 'page08.pre' 'failed' - if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ - && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then - md5sum -c << SHAR_EOF >/dev/null 2>&1 \ - || $echo 'page08.pre:' 'MD5 check failed' -678ef0c3162d2a2739d0efdcfeac5cb9 page08.pre -SHAR_EOF - else - shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'page08.pre'`" - test 715 -eq "$shar_count" || - $echo 'page08.pre:' 'original size' '715,' 'current size' "$shar_count!" - fi -fi -rm -fr _sh22890 -exit 0 diff --git a/docs/tutorials/005/page01.html b/docs/tutorials/005/page01.html deleted file mode 100644 index 90a5da1e1f4..00000000000 --- a/docs/tutorials/005/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="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>In this tutorial, we're going to flash-back to the simple server we -created a while back. We'll create a very simple server where everything -takes place in one thread. Once we have a solid understanding there, -we'll move on to the next tutorial where we begin to introduce concurrency -concepts. - -<P>There are four C++ source files in this tutorial: server.cpp, -client_acceptor.h, client_handler.h and client_handler.cpp. I'll -talk about each of these in turn with the usual color commentary as we -go. In addition, I'll briefly discuss the Makefile and a short perl -script I've added. - -<P> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page02.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/005/page02.html b/docs/tutorials/005/page02.html deleted file mode 100644 index 2a3e4b143de..00000000000 --- a/docs/tutorials/005/page02.html +++ /dev/null @@ -1,148 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>We begin with <I><A HREF="server.cpp">server.cpp</A></I>. -<P> -Abstraction by Kirthika: -<UL> -This tutorial is a re-cap of the client-server hookup tutorial with much - cleaner code (for instance: use of destroy() to delete objects and -process() which does the task of reading in data from the client). -<P> -We again enroll the services of the ACE_Reactor to handle events. Everything -occurs in a single thread. -<P> -This tutorial is a stepping stone towards a mutithreaded server model. -</ul> -<P> -<HR WIDTH="100%"> -<PRE> -<font color=red>// $Id$</font> - -<font color=red>/* 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 "<font color=green>real work</font>". */</font> - -<font color=blue>#include</font> "<font color=green>client_acceptor.h</font>" - -<font color=red>/* 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. */</font> - -static sig_atomic_t finished = 0; -extern "<font color=green>C</font>" void handler (int) -{ - finished = 1; -} - -<font color=red>/* A server has to listen for clients at a known TCP/IP port. The - default ACE port is 10002 (at least on my system) and that's good - enough for what we want to do here. Obviously, a more robust - application would take a command line parameter or read from a - configuration file or do some other clever thing. Just like the - signal handler above, though, that's not what we want to focus on, - so we're taking the easy way out. */</font> - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -<font color=red>/* 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. */</font> - -int -main (int argc, char *argv[]) -{ - <font color=red>/* 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. */</font> - ACE_Reactor reactor; - - <font color=red>/* 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.) */</font> - Client_Acceptor peer_acceptor; - - <font color=red>/* Create an ACE_INET_Addr that represents our endpoint of a - connection. We then open our acceptor object with that Addr. - Doing so tells the acceptor where to listen for connections. - Servers generally listen at "<font color=green>well known</font>" 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. */</font> - if (peer_acceptor.open (ACE_INET_Addr (PORT), - &reactor) == -1) - ACE_ERROR_RETURN ((LM_ERROR, - "<font color=green>%p\n</font>", - "<font color=green>open</font>"), - -1); - - <font color=red>/* Here, we know that the open was successful. If it had failed, we - would have exited above. A nice side-effect of the open() is that - we're already registered with the reactor we provided it. */</font> - - <font color=red>/* 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 "<font color=green>real</font>" work. Our simple - flag-setter doesn't justify deriving from ACE_Event_Handler and - providing a callback function though. */</font> - ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - <font color=red>/* 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. */</font> - ACE_DEBUG ((LM_DEBUG, - "<font color=green>(%P|%t) starting up server daemon\n</font>")); - - <font color=red>/* This will loop "<font color=green>forever</font>" 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 'restart' flag on the - open() method of ACE_Reactor if you're interested.) */</font> - while (!finished) - reactor.handle_events (); - - ACE_DEBUG ((LM_DEBUG, - "<font color=green>(%P|%t) shutting down server daemon\n</font>")); - - return 0; -} - -<font color=blue>#if defined</font> (<font color=purple>ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION</font>) -template class ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -<font color=blue>#elif defined</font> (<font color=purple>ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA</font>) -<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR> -<font color=blue>#pragma</font> <font color=purple>instantiate</font> ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -<font color=blue>#endif</font> <font color=red>/* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page03.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/005/page03.html b/docs/tutorials/005/page03.html deleted file mode 100644 index c190dfe9839..00000000000 --- a/docs/tutorials/005/page03.html +++ /dev/null @@ -1,71 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Now, let's take a look at <I><A HREF="client_acceptor.h">client_acceptor.h</A></I>. -Since I went on about how it does all the work of letting clients connect -to us, it must be rather complex. Right? Wrong. - -<P>The more you use ACE, the more you'll find that they've already taken -care of most details for you. With respect to the acceptance of client -connections: there just aren't that many ways to do it! The -ACE team has chosen an approach and created a C++ template that does -all of the work for you. All you're required to do is provide it -with an object type to instantiate when a new connection arrives. - -<P> -<HR WIDTH="100%"> -<PRE> -<font color=red>// $Id$</font> - -<font color=blue>#ifndef</font> <font color=purple>CLIENT_ACCEPTOR_H</font> -<font color=blue>#define</font> <font color=purple>CLIENT_ACCEPTOR_H</font> - -<font color=red>/* 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. */</font> - -<font color=blue>#include</font> "<A HREF="../../../ace/Acceptor.h">ace/Acceptor.h</A>" - -<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>) -<font color=blue># pragma</font> <font color=purple>once</font> -<font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font> - -<font color=red>/* Since we want to work with sockets, we'll need a SOCK_Acceptor to - allow the clients to connect to us. */</font> -<font color=blue>#include</font> "<A HREF="../../../ace/SOCK_Acceptor.h">ace/SOCK_Acceptor.h</A>" - -<font color=red>/* 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. */</font> -<font color=blue>#include</font> "<font color=green>client_handler.h</font>" - -<font color=red>/* 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! */</font> -typedef ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR> Client_Acceptor; - -<font color=blue>#endif</font> <font color=red>/* CLIENT_ACCEPTOR_H */</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page04.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/005/page04.html b/docs/tutorials/005/page04.html deleted file mode 100644 index fb670bbe7a3..00000000000 --- a/docs/tutorials/005/page04.html +++ /dev/null @@ -1,133 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Ok, so we've got a main() loop that sets up the acceptor and we've seen -how easy it is to create the acceptor object. So far, we've hardly -written any code at all. Well, that's just about to change... - -<P>First, we look at <I><A HREF="client_handler.h">client_handler.h</A></I> -for the declaration of the Client_Handler object. Then we look at -the definition where all of the real work of the application takes place. - -<P> -<HR WIDTH="100%"> - -<PRE> -<font color=red>// $Id$</font> - -<font color=blue>#ifndef</font> <font color=purple>CLIENT_HANDLER_H</font> -<font color=blue>#define</font> <font color=purple>CLIENT_HANDLER_H</font> - -<font color=red>/* 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 actual 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. */</font> - -<font color=blue>#include</font> "<A HREF="../../../ace/Svc_Handler.h">ace/Svc_Handler.h</A>" - -<font color=blue>#if !defined</font> (<font color=purple>ACE_LACKS_PRAGMA_ONCE</font>) -<font color=blue># pragma</font> <font color=purple>once</font> -<font color=blue>#endif</font> <font color=red>/* ACE_LACKS_PRAGMA_ONCE */</font> - -<font color=blue>#include</font> "<A HREF="../../../ace/SOCK_Stream.h">ace/SOCK_Stream.h</A>" - -<font color=red>/* Another feature of ACE_Svc_Handler is it's ability to present the - ACE_Task<> interface as well. That's what the ACE_NULL_SYNCH - parameter below is all about. That's beyond our scope here but - we'll come back to it in the next tutorial when we start looking at - concurrency options. */</font> -class Client_Handler : public ACE_Svc_Handler <ACE_SOCK_STREAM, ACE_NULL_SYNCH> -{ -public: - <font color=red>// Constructor...</font> - Client_Handler (void); - - <font color=red>/* 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. */</font> - void destroy (void); - - <font color=red>/* 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 an override. 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. */</font> - int open (void *acceptor); - - <font color=red>/* 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... As a - side-effect, the reactor will also invoke remove_handler() for the - object on the mask that caused the -1 return. This means that we - don't have to do that ourselves! */</font> - int handle_close (ACE_HANDLE handle, - ACE_Reactor_Mask mask); - -protected: - - <font color=red>/* 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 _handle 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 its 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 <handle> would - be important to us for reading the client's data. */</font> - int handle_input (ACE_HANDLE handle); - - <font color=red>/* This has nothing at all to do with ACE. I've added this here as - a worker function which I will call from handle_input(). That - allows me to introduce concurrency in later tutorials with no - changes to the worker function. You can think of process() as - application-level code and everything else as - application-framework code. */</font> - int process (char *rdbuf, int rdbuf_len); - - <font color=red>/* 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. */</font> - ~Client_Handler (void); -}; - -<font color=blue>#endif</font> <font color=red>/* CLIENT_HANDLER_H */</font> -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page05.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/005/page05.html b/docs/tutorials/005/page05.html deleted file mode 100644 index 388a421eff6..00000000000 --- a/docs/tutorials/005/page05.html +++ /dev/null @@ -1,249 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Now we're finally at <I><A HREF="client_handler.cpp">client_handler.cpp</A></I> -where we have to write some code. This file has more code than the -rest of the application all together. - -<P> -<HR WIDTH="100%"> -<PRE> -<font color=red>// $Id$</font> - -<font color=red>/* 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. */</font> -<font color=blue>#include</font> "<font color=green>client_acceptor.h</font>" -<font color=blue>#include</font> "<font color=green>client_handler.h</font>" - -<font color=red>/* 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... */</font> -<font color=#008888>Client_Handler::Client_Handler</font> (void) -{ -} - -<font color=red>/* 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. */</font> -<font color=#008888>Client_Handler::~Client_Handler</font> (void) -{ - <font color=red>// Make sure that our peer closes when we're deleted. This</font> - <font color=red>// will probably happened when the peer is deleted but it</font> - <font color=red>// doesn't hurt to be explicit.</font> - this->peer ().close (); -} - -<font color=red>/* 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. */</font> -void -<font color=#008888>Client_Handler::destroy</font> (void) -{ - <font color=red>/* 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! */</font> - this->reactor ()->remove_handler (this, - ACE_Event_Handler:: READ_MASK | <font color=#008888>ACE_Event_Handler::DONT_CALL</font>); - - <font color=red>/* 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. */</font> - delete this; -} - -<font color=red>/* 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... */</font> -int -<font color=#008888>Client_Handler::open</font> (void *_acceptor) -{ - <font color=red>/* Convert the void* to a Client_Acceptor*. You should probably use - those fancy ACE_*_cast macros 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. */</font> - Client_Acceptor *acceptor = (Client_Acceptor *) _acceptor; - - <font color=red>/* Our reactor reference will be set when we register ourselves but - I decided to go ahead and set it here. No good reason really... */</font> - this->reactor (acceptor->reactor ()); - - <font color=red>/* 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. */</font> - ACE_INET_Addr addr; - - <font color=red>/* 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 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. */</font> - if (this->peer ().get_remote_addr (addr) == -1) - return -1; - - <font color=red>/* 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, register 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. */</font> - if (this->reactor ()->register_handler (this, - <font color=#008888>ACE_Event_Handler::READ_MASK</font>) == -1) - ACE_ERROR_RETURN ((LM_ERROR, - "<font color=green>(%P|%t) can't register with reactor\n</font>"), - -1); - - <font color=red>/* 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. */</font> - ACE_DEBUG ((LM_DEBUG, - "<font color=green>(%P|%t) connected with %s\n</font>", - addr.get_host_name ())); - - <font color=red>/* Always return zero on success. */</font> - return 0; -} - -<font color=red>/* 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. */</font> -int -<font color=#008888>Client_Handler::handle_input</font> (ACE_HANDLE handle) -{ - <font color=red>/* Some compilers don't like it when you fail to use a parameter. - This macro will keep 'em quiet for you. */</font> - ACE_UNUSED_ARG (handle); - - <font color=red>/* 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. */</font> - char buf[BUFSIZ]; - - <font color=red>/* 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. */</font> - return this->process (buf, sizeof (buf)); -} - -<font color=red>/* If we return -1 out of handle_input() or if the reactor sees other - problems with us then handle_close() will be called. The reactor - framework will take care of removing us (due to the -1), so we - don't need to use the destroy() method. Instead, we just delete - ourselves directly. */</font> -int -<font color=#008888>Client_Handler::handle_close</font> (ACE_HANDLE handle, - ACE_Reactor_Mask mask) -{ - ACE_UNUSED_ARG (handle); - ACE_UNUSED_ARG (mask); - - delete this; - return 0; -} - -<font color=red>/* 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. */</font> -int -<font color=#008888>Client_Handler::process</font> (char *rdbuf, - int rdbuf_len) -{ - <font color=red>/* 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. */</font> - switch (this->peer ().recv (rdbuf, rdbuf_len)) - { - case -1: <font color=red>// Complain and leave</font> - ACE_ERROR_RETURN ((LM_ERROR, - "<font color=green>(%P|%t) %p bad read\n</font>", - "<font color=green>client</font>"), - -1); - case 0: <font color=red>// Complain and leave</font> - ACE_ERROR_RETURN ((LM_ERROR, - "<font color=green>(%P|%t) closing daemon (fd = %d)\n</font>", - this->get_handle ()), - -1); - default: <font color=red>// Show the data</font> - ACE_DEBUG ((LM_DEBUG, - "<font color=green>(%P|%t) from client: %s</font>", - rdbuf)); - } - - <font color=red>/* It's also worth mentioning that recv() has a cousin: recv_n(). - recv_n() will receive exactly the number of bytes you provide it. - This is very good when you know exactly how much you expect to - receive. For the application here, unfortunately, we don't have - any idea how much the client will be sending. recv() will read - up-to-but-not-more-than the number of bytes we specify (e.g. -- - _rdbuf_len). That works well when we don't know how much the - client will provide. */</font> - - return 0; -} -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page06.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/005/page06.html b/docs/tutorials/005/page06.html deleted file mode 100644 index 9fbe678e023..00000000000 --- a/docs/tutorials/005/page06.html +++ /dev/null @@ -1,144 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>Before we go, I wanted you to see the <A HREF="Makefile">Makefile</A>. - -<P> -<HR WIDTH="100%"> -<PRE> -#---------------------------------------------------------------------------- -# $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 - # "<font color=green>app.mk</font>" that includes all of these. Our project makefiles then just - # need to include app.mk to get everything they need. - -include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU -include $(ACE_ROOT)/include/makeinclude/macros.GNU -include $(ACE_ROOT)/include/makeinclude/rules.common.GNU -include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU -include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU -include $(ACE_ROOT)/include/makeinclude/rules.local.GNU - -#---------------------------------------------------------------------------- -# Local targets -#---------------------------------------------------------------------------- - - # Sometimes I like to reformat my code to make it more readable. This is - # more useful for the comments than anything else. Unfortunately, the - # "<font color=green>indent</font>" 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 "<font color=green>depend</font>". 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 "<font color=green>.depend</font>" which we then - <font color=blue># include</font> just like the makefile components above. - # - # NOTE: The 'depend' target expects to have GCC available. - # You can do the same thing with other compilers but the ACE - # makefiles and utilities are only wired up to work with GCC. -Depend : depend - perl ../fix.Makefile - -.depend : # - touch .depend - - -HTML : # - [ -f hdr ] || $(MAKE) UNSHAR - perl ../combine *.pre ; chmod +r *.html - -SHAR : # - [ ! -f combine.shar ] || exit 1 - shar -T hdr bodies *.pre > combine.shar && rm -f hdr bodies *.pre *.pst - -UNSHAR : # - sh combine.shar - -CLEAN : realclean - rm -f hdr bodies *.pre *.pst .depend - -#---------------------------------------------------------------------------- -# Dependencies -#---------------------------------------------------------------------------- - - # Don't put anything below here. Between the "<font color=green>depend</font>" target and fix.Makefile - # it's guaranteed to be lost! - - # This is inserted by the fix.Makefile script -include .depend -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page07.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/005/page07.html b/docs/tutorials/005/page07.html deleted file mode 100644 index 3a7433dbd34..00000000000 --- a/docs/tutorials/005/page07.html +++ /dev/null @@ -1,95 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>And last (and probably least) is the <A HREF="../fix.Makefile">perl script</A> -that pulls the dependency stuff out of Makefile and into .depend. - -<P> -<HR WIDTH="100%"> -<PRE> -eval '(exit $?0)' && eval 'exec perl -w -S $0 ${1+"<font color=green>$@</font>"}' - & eval 'exec perl -S $0 $argv:q' - if 0; - -require "<font color=green>getopts.pl</font>"; -&Getopts("<font color=green>f:o:</font>"); - -$opt_f = "<font color=green>Makefile</font>" if( ! $opt_f ); -$opt_o = "<font color=green>.depend</font>" if( ! $opt_o ); - - # Open the Makefile that has been mangled by 'make depend' - # and suck it into a perl array. -open(IF,"<font color=green><$opt_f</font>") || 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,"<font color=green>>$opt_o</font>") || die; -open(MF,"<font color=green>>$opt_f.tmp</font>") || 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 - # "<font color=green>make depend</font>" causes to be inserted. - # - if( m/^\Q# DO NOT DELETE THIS LINE -- g++dep uses it.\E/ ) { - - # If so, change our "<font color=green>mode</font>" and skip this line. - ++$depend; - next; - } - - # Also skip the "<font color=green>include .depend</font>" that we insert. If we - # don't do this, it is possible to have a bunch of these - # inserted into the output when we read an unmangled Makefile - next if( m/^include $opt_o/ ); - - # Print the non-dependency info to the temporary Makefile - print MF $_; - } -} - -# Tell our new Makefile to include the dependency file -print MF "<font color=green>include $opt_o\n</font>"; - -# 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("<font color=green>$opt_f</font>"); -rename("<font color=green>$opt_f.tmp</font>","<font color=green>$opt_f</font>"); - -exit(0); -</PRE> -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] [<A HREF="page08.html">Continue This Tutorial</A>]</CENTER> diff --git a/docs/tutorials/005/page08.html b/docs/tutorials/005/page08.html deleted file mode 100644 index db7acc3f76b..00000000000 --- a/docs/tutorials/005/page08.html +++ /dev/null @@ -1,47 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]"> - <META NAME="Author" CONTENT="Billy Quinn"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 005</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 005</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>On the road to a multithreaded server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P>That's it for Tutorial 5. In this tutorial we've built a single-threaded -reactor-based server. We've done a couple of things that aren't exactly -necessary for such an implementation but I plan to build on that as -we explore two other concurrency strategies: thread per connection -and thread pool. - -<P>For reference, here's the file list again: -<UL> -<LI> -<A HREF="Makefile">Makefile</A></LI> - -<LI> -<A HREF="client_acceptor.h">client_acceptor.h</A></LI> - -<LI> -<A HREF="client_handler.cpp">client_handler.cpp</A></LI> - -<LI> -<A HREF="client_handler.h">client_handler.h</A></LI> - -<LI> -<A HREF="server.cpp">server.cpp</A></LI> - -<LI> -<A HREF="../fix.Makefile">fix.Makefile</A></LI> -</UL> - -<P><HR WIDTH="100%"> -<CENTER>[<A HREF="../online-tutorials.html">Tutorial Index</A>] </CENTER> diff --git a/docs/tutorials/005/server.brk b/docs/tutorials/005/server.brk deleted file mode 100644 index ba3d878a1da..00000000000 --- a/docs/tutorials/005/server.brk +++ /dev/null @@ -1,154 +0,0 @@ - -#include "ace/Acceptor.h" -#include "ace/SOCK_Acceptor.h" -#include "ace/Reactor.h" -#include "ace/Thread.h" - - -ACE_Reactor * g_reactor; - -static sig_atomic_t finished = 0; - -class Logging_Handler; - -extern "C" void handler (int) { finished = 1; } - - - -class Reactor_Derived : public ACE_Reactor -{ - -public : - Reactor_Derived() : () - { - counter = 0; - } - - virtual ~Reactor_Derived() - { - cout << "*****Calling the reactor destructor*****" << endl; - } - -private : - friend class Logging_Handler; - - // counter is used to keep track of the number of service handlers - // registered with this reactor (Surely theres a better way ;-) - int counter; -}; - -class Logging_Handler : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -{ - -public: - - Logging_Handler (void) { }; - - virtual void destroy (void) - { - if (this->thread_reactorP->remove_handler(this, - ACE_Event_Handler::READ_MASK | ACE_Event_Handler::DONT_CALL) == -1 - ) - ACE_ERROR_RETURN ((LM_ERROR, "can'(%P|%t) t remove service from reactor\n"), -1); - - // Decrement the handler tracking variable in the reactor to - // indicate this service handler has terminated - --thread_reactorP->counter; - - this->peer ().close (); - delete this; - } - - static void *run_thread(Logging_Handler *this_) - { - Reactor_Derived thread_reactor; - - this_->thread_reactorP = &thread_reactor; - - // Increment our handler counter to account for this service handler - ++thread_reactor.counter; - - if (thread_reactor.register_handler(this_, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR,"can'(%P|%t) t register with reactor\n"), -1); - - while( thread_reactor.counter > 0 ) - { - // If thread_reactor.counter = 0 then we have no more service - // handlers connected to the reactor. We set a timeout value - // of 1 second so that the handle_events loop break out every - // second to check on the count ( because of it blocking - // even when there are no connections we need to do this) - thread_reactor.handle_events(ACE_Time_Value(1,0)); - } - } - - virtual int open (void *) - { - ACE_Thread::spawn(&Logging_Handler::run_thread,this); - return 0; - } - - virtual int close (u_long) - { - this->destroy (); - return 0; - } - -protected: - - virtual int handle_input (ACE_HANDLE) - { - char buf[128]; - memset(buf,0,sizeof(buf)); - - switch( this->peer().recv(buf,sizeof buf) ) - { - case -1: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) %p bad read\n", "client logger"), -1); - case 0: - ACE_ERROR_RETURN ((LM_ERROR, "(%P|%t) closing log daemon (fd = %d)\n", this->get_handle ()), -1); - default: - ACE_DEBUG ((LM_DEBUG, "(%p|%t) from client : %s",buf)); - } - - return 0; - } - - -private: - Reactor_Derived *thread_reactorP; -}; - - -typedef ACE_Acceptor <Logging_Handler, ACE_SOCK_ACCEPTOR> Logging_Acceptor; - - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -int main (int argc, char *argv[]) -{ - g_reactor = new ACE_Reactor; - - // Acceptor factory. - Logging_Acceptor peer_acceptor; - - if (peer_acceptor.open (ACE_INET_Addr (PORT)) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"), -1); - - else if (g_reactor->register_handler (&peer_acceptor, ACE_Event_Handler::READ_MASK) == -1) - ACE_ERROR_RETURN ((LM_ERROR, "registering service with ACE_Reactor\n"), -1); - - ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - // Run forever, performing logging service. - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server logging daemon\n")); - - // Perform logging service until QUIT_HANDLER receives SIGINT. - while ( !finished ) - g_reactor->handle_events (); - - ACE_DEBUG ((LM_DEBUG, "(%P|%t) shutting down server logging daemon\n")); - - return 0; -} diff --git a/docs/tutorials/005/server.cpp b/docs/tutorials/005/server.cpp deleted file mode 100644 index 00f2f6778ae..00000000000 --- a/docs/tutorials/005/server.cpp +++ /dev/null @@ -1,111 +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 not what we want to focus on, - so we're taking the easy way out. */ - -static const u_short PORT = ACE_DEFAULT_SERVER_PORT; - -/* Finally, we get to main. Some C++ compilers will complain loudly - if your function signature doesn't match the prototype. Even - though we're not going to use the parameters, we still have to - specify them. */ - -int -main (int argc, char *argv[]) -{ - /* In our earlier servers, we used a global pointer to get to the - reactor. I've never really liked that idea, so I've moved it into - main() this time. When we get to the Client_Handler object you'll - see how we manage to get a pointer back to this reactor. */ - ACE_Reactor reactor; - - /* The acceptor will take care of letting clients connect to us. It - will also arrange for a Client_Handler to be created for each new - client. Since we're only going to listen at one TCP/IP port, we - only need one acceptor. If we wanted, though, we could create - several of these and listen at several ports. (That's what we - would do if we wanted to rewrite inetd for instance.) */ - Client_Acceptor peer_acceptor; - - /* Create an ACE_INET_Addr that represents our endpoint of a - connection. We then open our acceptor object with that Addr. - Doing so tells the acceptor where to listen for connections. - Servers generally listen at "well known" addresses. If not, there - must be some mechanism by which the client is informed of the - server's address. - - Note how ACE_ERROR_RETURN is used if we fail to open the acceptor. - This technique is used over and over again in our tutorials. */ - if (peer_acceptor.open (ACE_INET_Addr (PORT), - &reactor) == -1) - ACE_ERROR_RETURN ((LM_ERROR, - "%p\n", - "open"), - -1); - - /* Here, we know that the open was successful. If it had failed, we - would have exited above. A nice side-effect of the open() is that - we're already registered with the reactor we provided it. */ - - /* Install our signal handler. You can actually register signal - handlers with the reactor. You might do that when the signal - handler is responsible for performing "real" work. Our simple - flag-setter doesn't justify deriving from ACE_Event_Handler and - providing a callback function though. */ - ACE_Sig_Action sa ((ACE_SignalHandler) handler, SIGINT); - - /* Like ACE_ERROR_RETURN, the ACE_DEBUG macro gets used quite a bit. - It's a handy way to generate uniform debug output from your - program. */ - ACE_DEBUG ((LM_DEBUG, - "(%P|%t) starting up server daemon\n")); - - /* This will loop "forever" invoking the handle_events() method of - our reactor. handle_events() watches for activity on any - registered handlers and invokes their appropriate callbacks when - necessary. Callback-driven programming is a big thing in ACE, you - should get used to it. If the signal handler catches something, - the finished flag will be set and we'll exit. Conveniently - enough, handle_events() is also interrupted by signals and will - exit back to the while() loop. (If you want your event loop to - not be interrupted by signals, checkout the 'restart' flag on the - open() method of ACE_Reactor if you're interested.) */ - while (!finished) - reactor.handle_events (); - - ACE_DEBUG ((LM_DEBUG, - "(%P|%t) shutting down server daemon\n")); - - return 0; -} - -#if defined (ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION) -template class ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR>; -template class ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>; -#elif defined (ACE_HAS_TEMPLATE_INSTANTIATION_PRAGMA) -#pragma instantiate ACE_Acceptor <Client_Handler, ACE_SOCK_ACCEPTOR> -#pragma instantiate ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> -#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION */ |