diff options
Diffstat (limited to 'docs/tutorials/006/page05.html')
-rw-r--r-- | docs/tutorials/006/page05.html | 516 |
1 files changed, 0 insertions, 516 deletions
diff --git a/docs/tutorials/006/page05.html b/docs/tutorials/006/page05.html deleted file mode 100644 index 5f8bedf16d9..00000000000 --- a/docs/tutorials/006/page05.html +++ /dev/null @@ -1,516 +0,0 @@ -<HTML> -<HEAD> - <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> - <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]"> - <META NAME="Author" CONTENT="James CE Johnson"> - <META NAME="Description" CONTENT="A first step towards using ACE productively"> - <TITLE>ACE Tutorial 006</TITLE> -</HEAD> -<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> - -<CENTER><B><FONT SIZE=+2>ACE Tutorial 006</FONT></B></CENTER> - -<CENTER><B><FONT SIZE=+2>Creating a thread-per-connection server</FONT></B></CENTER> - - -<P> -<HR WIDTH="100%"> - -<P><A HREF="client_handler.cpp">client_handler.cpp</A> exposes all the -things I've been hinting at. Pay special attention to the decision -made in open() as well as the bit of cleverness in svc(). - -<P> -<HR WIDTH="100%"> - -<P><FONT FACE="Arial,Helvetica">// $Id: client_handler.cpp,v 1.1 1998/08/30 -23:47:13 schmidt Exp $</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In client_handler.h I alluded -to the fact that we'll mess around with a</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor pointer. -To do so, we need the Client_Acceptor object</FONT> -<BR><FONT FACE="Arial,Helvetica"> declaration.</FONT> - -<P><FONT FACE="Arial,Helvetica"> We know that including client_handler.h -is redundant because</FONT> -<BR><FONT FACE="Arial,Helvetica"> client_acceptor.h includes -it. Still, the sentry prevents double-inclusion</FONT> -<BR><FONT FACE="Arial,Helvetica"> from causing problems and -it's sometimes good to be explicit about what</FONT> -<BR><FONT FACE="Arial,Helvetica"> we're using.</FONT> - -<P><FONT FACE="Arial,Helvetica"> On the other hand, we don't -directly include any ACE header files here.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_acceptor.h"</FONT> -<BR><FONT FACE="Arial,Helvetica">#include "client_handler.h"</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our constructor doesn't do -anything. That's generally a good idea. Unless</FONT> -<BR><FONT FACE="Arial,Helvetica"> you want to start throwing -exceptions, there isn't a really good way to</FONT> -<BR><FONT FACE="Arial,Helvetica"> indicate that a constructor -has failed. If I had my way, I'd have a boolean</FONT> -<BR><FONT FACE="Arial,Helvetica"> return code from it that -would cause new to return 0 if I failed. Oh</FONT> -<BR><FONT FACE="Arial,Helvetica"> well...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Handler::Client_Handler (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our destructor doesn't do -anything either. That is also by design.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Remember, we really want -folks to use destroy() to get rid of us. If that's</FONT> -<BR><FONT FACE="Arial,Helvetica"> so, then there's nothing -left to do when the destructor gets invoked.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">Client_Handler::~Client_Handler (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The much talked about destroy() -method! The reason I keep going on about</FONT> -<BR><FONT FACE="Arial,Helvetica"> this is because it's just -a Bad Idea (TM) to do real work inside of a</FONT> -<BR><FONT FACE="Arial,Helvetica"> destructor. Although -this method is void, it really should return</FONT> -<BR><FONT FACE="Arial,Helvetica"> int so that it can tell the -caller there was a problem. Even as</FONT> -<BR><FONT FACE="Arial,Helvetica"> void you could at least throw -an exception which you would never want</FONT> -<BR><FONT FACE="Arial,Helvetica"> to do in a destructor.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">void Client_Handler::destroy (void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We probably got -here because of an error on the stream, so the peer</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection is -probably already closed. Still... there are other ways to</FONT> -<BR><FONT FACE="Arial,Helvetica"> get here and -closing a closed peer doesn't hurt.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->peer ().close ();</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Tell the reactor -to forget all about us. Notice that we use the same args</FONT> -<BR><FONT FACE="Arial,Helvetica"> here that we -use in the open() method to register ourselves. In addition,</FONT> -<BR><FONT FACE="Arial,Helvetica"> we use the DONT_CALL -flag to prevent handle_close() being called. Since we</FONT> -<BR><FONT FACE="Arial,Helvetica"> likely got here -due to handle_close(), that could cause a bit of nasty</FONT> -<BR><FONT FACE="Arial,Helvetica"> recursion!</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->reactor ()->remove_handler -(this,</FONT> -<BR><FONT FACE="Arial,Helvetica"> -ACE_Event_Handler:: READ_MASK | ACE_Event_Handler::DONT_CALL);</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> This is how we're -able to tell folks not to use delete. By</FONT> -<BR><FONT FACE="Arial,Helvetica"> deleting our -own instance, we take care of memory leaks after ensuring</FONT> -<BR><FONT FACE="Arial,Helvetica"> that the object -is shut down correctly.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> delete this;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As mentioned before, the -open() method is called by the Client_Acceptor when</FONT> -<BR><FONT FACE="Arial,Helvetica"> a new client connection has -been accepted. The Client_Acceptor instance</FONT> -<BR><FONT FACE="Arial,Helvetica"> pointer is cast to a void* -and given to us here. We'll use that to avoid</FONT> -<BR><FONT FACE="Arial,Helvetica"> some global data...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::open (void *_acceptor)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> We need this -to store the address of the client that we are now connected</FONT> -<BR><FONT FACE="Arial,Helvetica"> to. We'll -use it later to display a debug message.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_INET_Addr addr;</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our ACE_Svc_Handler -baseclass gives us the peer() method as a way to</FONT> -<BR><FONT FACE="Arial,Helvetica"> access our underlying -ACE_SOCK_Stream. On that object, we can invoke the</FONT> -<BR><FONT FACE="Arial,Helvetica"> get_remote_addr() -method to get get an ACE_INET_Addr having our client's</FONT> -<BR><FONT FACE="Arial,Helvetica"> address information. -As with most ACE methods, we'll get back (and return)</FONT> -<BR><FONT FACE="Arial,Helvetica"> a -1 if there -was any kind of error. Once we have the ACE_INET_Addr, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> can query it -to find out the clien's host name, TCP/IP address, TCP/IP</FONT> -<BR><FONT FACE="Arial,Helvetica"> port value and -so forth. One word of warning: the get_host_name()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method of ACE_INET_Addr -may return you an empty string if your name server</FONT> -<BR><FONT FACE="Arial,Helvetica"> can't resolve -it. On the other hand, get_host_addr() will always give you</FONT> -<BR><FONT FACE="Arial,Helvetica"> the dotted-decimal -string representing the TCP/IP address.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (this->peer ().get_remote_addr -(addr) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return --1;</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Convert the void* -to a Client_Acceptor*. You should probably use those</FONT> -<BR><FONT FACE="Arial,Helvetica"> fancy new C++ -cast operators but I can never remember how/when to do so.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since you can -cast just about anything around a void* without compiler</FONT> -<BR><FONT FACE="Arial,Helvetica"> warnings be very -sure of what you're doing when you do this kind of thing.</FONT> -<BR><FONT FACE="Arial,Helvetica"> That's where -the new-style cast operators can save you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> Client_Acceptor *acceptor = (Client_Acceptor -*) _acceptor;</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our Client_Acceptor -is constructed with a concurrency strategy. Here, we</FONT> -<BR><FONT FACE="Arial,Helvetica"> go back to it -to find out what that strategy was. If thread-per-connection</FONT> -<BR><FONT FACE="Arial,Helvetica"> was selected -then we simply activate a thread for ourselves and exit. Our</FONT> -<BR><FONT FACE="Arial,Helvetica"> svc() method -will then begin executing in that thread.</FONT> - -<P><FONT FACE="Arial,Helvetica"> If we are told -to use the single-threaded strategy, there is no difference</FONT> -<BR><FONT FACE="Arial,Helvetica"> between this -and the Tutorial 5 implementation.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( acceptor->thread_per_connection() -)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return this->activate();</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Our reactor reference -will be set when we register ourselves but I decided</FONT> -<BR><FONT FACE="Arial,Helvetica"> to go ahead and -set it here. No good reason really...</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> this->reactor (acceptor->reactor -());</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If we managed -to get the client's address then we're connected to a real</FONT> -<BR><FONT FACE="Arial,Helvetica"> and valid client. -I suppose that in some cases, the client may connect</FONT> -<BR><FONT FACE="Arial,Helvetica"> and disconnect -so quickly that it is invalid by the time we get here. In</FONT> -<BR><FONT FACE="Arial,Helvetica"> any case, the -test above should always be done to ensure that the</FONT> -<BR><FONT FACE="Arial,Helvetica"> connection is -worth keeping.</FONT> - -<P><FONT FACE="Arial,Helvetica"> Now, regiser ourselves -with a reactor and tell that reactor that we want</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be notified -when there is something to read. Remember, we took our</FONT> -<BR><FONT FACE="Arial,Helvetica"> reactor value -from the acceptor which created us in the first place.</FONT> -<BR><FONT FACE="Arial,Helvetica"> Since we're exploring -a single-threaded implementation, this is the</FONT> -<BR><FONT FACE="Arial,Helvetica"> correct thing -to do.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if (this->reactor ()->register_handler -(this, ACE_Event_Handler::READ_MASK) == -1)</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) can't register with reactor\n"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Here, we use -the ACE_INET_Addr object to print a message with the name of</FONT> -<BR><FONT FACE="Arial,Helvetica"> the client we're -connected to. Again, it is possible that you'll get an</FONT> -<BR><FONT FACE="Arial,Helvetica"> empty string -for the host name if your DNS isn't configured correctly or</FONT> -<BR><FONT FACE="Arial,Helvetica"> if there is some -other reason that a TCP/IP addreess cannot be converted</FONT> -<BR><FONT FACE="Arial,Helvetica"> into a host name.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG ((LM_DEBUG, "(%P|%t) -connected with %s\n", addr.get_host_name ()));</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Always return -zero on success.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> As mentioned in the header, -the typical way to close an object in a threaded</FONT> -<BR><FONT FACE="Arial,Helvetica"> context is to invoke it's -close() method. Since we already have a handle_close()</FONT> -<BR><FONT FACE="Arial,Helvetica"> method built to cleanup after -us, we'll just forward the request on to that</FONT> -<BR><FONT FACE="Arial,Helvetica"> object.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::close(u_long flags)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Down in the depths of our baseclass, this will eventually cause us</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to be destroyed. Since all of the destructors are virtual, everything</FONT> -<BR><FONT FACE="Arial,Helvetica"> -gets cleaned up nicely.</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -this->handle_close(ACE_INVALID_HANDLE,0);</FONT><FONT FACE="Arial,Helvetica"></FONT> - -<P><FONT FACE="Arial,Helvetica"> -/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Don't forward the close() to the baseclass! handle_close() above -has</FONT> -<BR><FONT FACE="Arial,Helvetica"> -already taken care of delete'ing. Forwarding close() would cause -that</FONT> -<BR><FONT FACE="Arial,Helvetica"> -to happen again and things would get really ugly at that point!</FONT> -<BR><FONT FACE="Arial,Helvetica"> -*/</FONT> -<BR><FONT FACE="Arial,Helvetica"> -return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> In the open() method, we -registered with the reactor and requested to be</FONT> -<BR><FONT FACE="Arial,Helvetica"> notified when there is data -to be read. When the reactor sees that activity</FONT> -<BR><FONT FACE="Arial,Helvetica"> it will invoke this handle_input() -method on us. As I mentioned, the _handle</FONT> -<BR><FONT FACE="Arial,Helvetica"> parameter isn't useful to -us but it narrows the list of methods the reactor</FONT> -<BR><FONT FACE="Arial,Helvetica"> has to worry about and the -list of possible virtual functions we would have</FONT> -<BR><FONT FACE="Arial,Helvetica"> to override.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::handle_input (ACE_HANDLE -_handle)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Some compilers -don't like it when you fail to use a parameter. This macro</FONT> -<BR><FONT FACE="Arial,Helvetica"> will keep 'em -quiet for you.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_handle);</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Now, we create -and initialize a buffer for receiving the data. Since this</FONT> -<BR><FONT FACE="Arial,Helvetica"> is just a simple -test app, we'll use a small buffer size.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, 0, sizeof (buf));</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Invoke the process() -method with a pointer to our data area. We'll let</FONT> -<BR><FONT FACE="Arial,Helvetica"> that method worry -about interfacing with the data. You might choose to go</FONT> -<BR><FONT FACE="Arial,Helvetica"> ahead and read -the data and then pass the result to process(). However,</FONT> -<BR><FONT FACE="Arial,Helvetica"> application logic -may require that you read a few bytes to determine what</FONT> -<BR><FONT FACE="Arial,Helvetica"> else to read... -It's best if we push that all into the application-logic</FONT> -<BR><FONT FACE="Arial,Helvetica"> level.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> return this->process (buf, sizeof -(buf));</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> If we return -1 out of handle_input() -or if the reactor sees other problems</FONT> -<BR><FONT FACE="Arial,Helvetica"> with us then handle_close() -will be called. It uses our destroy() method to</FONT> -<BR><FONT FACE="Arial,Helvetica"> shut us down cleanly and -get rid of our instance.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::handle_close (ACE_HANDLE -_handle, ACE_Reactor_Mask _mask)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_handle);</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_UNUSED_ARG (_mask);</FONT> - -<P><FONT FACE="Arial,Helvetica"> this->destroy ();</FONT> -<BR><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> The ACE_Svc_Handler<> -is ultimately derived from ACE_Task<>. If you want to</FONT> -<BR><FONT FACE="Arial,Helvetica"> create a multi-threaded application, -these are your tools! Simply override</FONT> -<BR><FONT FACE="Arial,Helvetica"> the svc() method in your -derivative and arrange for your activate() method</FONT> -<BR><FONT FACE="Arial,Helvetica"> to be called. The svc() -method then executes in the new thread.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::svc(void)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Like handle_input(), -we create a buffer for loading the data. Doing so</FONT> -<BR><FONT FACE="Arial,Helvetica"> in handle_input() -doesn't help any but there is a small performance increase</FONT> -<BR><FONT FACE="Arial,Helvetica"> by doing this -here: the buffer is created once when the thread is created</FONT> -<BR><FONT FACE="Arial,Helvetica"> instead of for -each invocation of process().</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> char buf[128];</FONT> - -<P><FONT FACE="Arial,Helvetica"> // Forever...</FONT> -<BR><FONT FACE="Arial,Helvetica"> while( 1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> // Clean the -buffer...</FONT> -<BR><FONT FACE="Arial,Helvetica"> memset (buf, -0, sizeof (buf));</FONT> - -<P><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> -Invoke the proces() method to read and process the data. This is</FONT> -<BR><FONT FACE="Arial,Helvetica"> -exactly the way it is used by handle_input(). That's the reason I</FONT> -<BR><FONT FACE="Arial,Helvetica"> -created process() in the first place: so that it can be used in either</FONT> -<BR><FONT FACE="Arial,Helvetica"> -concurrency strategy. Since process() has all of our application-level</FONT> -<BR><FONT FACE="Arial,Helvetica"> -logic, it's nice that it doesn't have to change when we decide to go</FONT> -<BR><FONT FACE="Arial,Helvetica"> -multi-threaded.</FONT> - -<P><FONT FACE="Arial,Helvetica"> -Notice that since the recv() method call in process() blocks until</FONT> -<BR><FONT FACE="Arial,Helvetica"> -there is data ready, this thread doesn't consume any CPU time until</FONT> -<BR><FONT FACE="Arial,Helvetica"> -there is actually data sent from the client.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> if( this->process(buf,sizeof(buf)) -== -1 )</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> return(-1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> return(0);</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P><FONT FACE="Arial,Helvetica">/*</FONT> -<BR><FONT FACE="Arial,Helvetica"> And, at last, we get to the -application-logic level. Out of everything</FONT> -<BR><FONT FACE="Arial,Helvetica"> we've done so far, this is -the only thing that really has anything to do</FONT> -<BR><FONT FACE="Arial,Helvetica"> with what your application -will do. In this method we will read and process</FONT> -<BR><FONT FACE="Arial,Helvetica"> the client's data. -In a real appliation, you will probably have a bit more</FONT> -<BR><FONT FACE="Arial,Helvetica"> in main() to deal with command -line options but after that point, all of the</FONT> -<BR><FONT FACE="Arial,Helvetica"> action takes place here.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica">int Client_Handler::process (char *_rdbuf, -int _rdbuf_len)</FONT> -<BR><FONT FACE="Arial,Helvetica">{</FONT> -<BR><FONT FACE="Arial,Helvetica"> /*</FONT> -<BR><FONT FACE="Arial,Helvetica"> Using the buffer -provided for us, we read the data from the client. If</FONT> -<BR><FONT FACE="Arial,Helvetica"> there is a read -error (eg -- recv() returns -1) then it's a pretty good</FONT> -<BR><FONT FACE="Arial,Helvetica"> bet that the -connection is gone. Likewise, if we read zero bytes then</FONT> -<BR><FONT FACE="Arial,Helvetica"> something wrong -has happened. The reactor wouldn't have called us if</FONT> -<BR><FONT FACE="Arial,Helvetica"> there wasn't -some kind of read activity but there wouldn't be activity if</FONT> -<BR><FONT FACE="Arial,Helvetica"> there were no -bytes to read...</FONT> - -<P><FONT FACE="Arial,Helvetica"> On the other hand, -if we got some data then we can display it in a debug</FONT> -<BR><FONT FACE="Arial,Helvetica"> message for everyone -to see.</FONT> -<BR><FONT FACE="Arial,Helvetica"> */</FONT> -<BR><FONT FACE="Arial,Helvetica"> switch (this->peer ().recv (_rdbuf, -_rdbuf_len))</FONT> -<BR><FONT FACE="Arial,Helvetica"> {</FONT> -<BR><FONT FACE="Arial,Helvetica"> case -1:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) %p bad read\n", "client"), -1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> case 0:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_ERROR_RETURN -((LM_ERROR, "(%P|%t) closing daemon (fd = %d)\n", this->get_handle ()), --1);</FONT> -<BR><FONT FACE="Arial,Helvetica"> default:</FONT> -<BR><FONT FACE="Arial,Helvetica"> ACE_DEBUG -((LM_DEBUG, "(%P|%t) from client: %s", _rdbuf));</FONT> -<BR><FONT FACE="Arial,Helvetica"> }</FONT> - -<P><FONT FACE="Arial,Helvetica"> return 0;</FONT> -<BR><FONT FACE="Arial,Helvetica">}</FONT> - -<P> -<HR WIDTH="100%"> - -<P>Well, that's it! After all the talk & the hype, you would -have expected it to be more difficult to create a multi-threaded server. -Surprise! It really is that easy. You still have to handle -contention issues which we haven't addressed here and that is a rather -nasty topic. Still, for the simple case, this is all you have to -do. - -<P>The next page is the last for this tutorial. Head on over there -& we'll round up the file list one last time. - -<P> -<HR WIDTH="100%"> -<CENTER>[<A HREF="..">Tutorial Index</A>] [<A HREF="page06.html">Continue -This Tutorial</A>]</CENTER> - -</BODY> -</HTML> |