Sophie

Sophie

distrib > Mandriva > current > i586 > media > main-updates > by-pkgid > ed376d6842ea322c25405e7c23b3bc12 > files > 657

libcommoncpp-devel-1.8.0-5.1mdv2010.1.i586.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<title>GNU CommonC++: tcpservice.cpp</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<link href="doxygen.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<!-- Generated by Doxygen 1.6.3 -->
<div class="navigation" id="top">
  <div class="tabs">
    <ul>
      <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
      <li><a href="namespaces.html"><span>Namespaces</span></a></li>
      <li><a href="annotated.html"><span>Classes</span></a></li>
      <li><a href="files.html"><span>Files</span></a></li>
      <li><a href="examples.html"><span>Examples</span></a></li>
    </ul>
  </div>
</div>
<div class="contents">
<h1>tcpservice.cpp</h1><div class="fragment"><pre class="fragment"><span class="comment">//</span>
<span class="comment">// tcpservice.cpp</span>
<span class="comment">//</span>
<span class="comment">//  Copyright 2000 - Gianni Mariani &lt;gianni@mariani.ws&gt;</span>
<span class="comment">//</span>
<span class="comment">//  An example of a simple chatty server using CommonC++.</span>
<span class="comment">//</span>
<span class="comment">//  This simple application basically operates as a</span>
<span class="comment">//  very simple chat system. From a telnet session</span>
<span class="comment">//  on localhost:3999 , any messages typed from a telnet</span>
<span class="comment">//  client are written to all participating sessions.</span>
<span class="comment">//</span>
<span class="comment">//  This is free software licensed under the terms of the GNU</span>
<span class="comment">//  Public License</span>
<span class="comment">//</span>
<span class="comment">//  This example:</span>
<span class="comment">//</span>
<span class="comment">//  This demostrates a simple threaded server, actually,</span>
<span class="comment">//  the sessions are not all threaded though they could be</span>
<span class="comment">//  if that&#39;s what you wanted.  Basically it demonstrates the</span>
<span class="comment">//  use of SocketService, SocketPorts and Threads.</span>
<span class="comment">//</span>
<span class="comment">//  For those familiar with Unix network programming, SocketService</span>
<span class="comment">//  basically encapsulates all the work to communicate with</span>
<span class="comment">//  the select() or poll() system calls.  SocketPorts are</span>
<span class="comment">//  basically encapsulations of sessions or open file descriptors.</span>
<span class="comment">//</span>
<span class="comment">//  Anyhow, this example is a very simple echo server but</span>
<span class="comment">//  it echos to all connected clients.  So it&#39;s a poor man&#39;s</span>
<span class="comment">//  IRC !  You connect via telnet to localhost port 3999 and</span>
<span class="comment">//  it will echo to all other connected clients what you type in !</span>
<span class="comment">//</span>

<span class="preprocessor">#include &lt;<a class="code" href="socketport_8h.html" title="Network service framework and design pattern.">cc++/socketport.h</a>&gt;</span>

<span class="preprocessor">#include &lt;iostream&gt;</span>

<span class="comment">// For starters, we need a thread safe list, we&#39;ll make one</span>
<span class="comment">// out of the STL list&lt;&gt; template -</span>
<span class="comment">//  http://www.sgi.com/Technology/STL/index.html</span>
<span class="comment">//</span>
<span class="comment">// Thread safe list class</span>
<span class="comment">//</span>
<span class="preprocessor">#include &lt;list&gt;</span>

<span class="preprocessor">#ifdef  CCXX_NAMESPACES</span>
<span class="preprocessor"></span><span class="keyword">using namespace </span>std;
<span class="keyword">using namespace </span>ost;
<span class="preprocessor">#endif</span>
<span class="preprocessor"></span>
<span class="keyword">class </span>ts_list_item;
<span class="keyword">typedef</span> list&lt;ts_list_item *&gt; ts_list;

<span class="comment">// a list head - containing a list and a Mutex.</span>
<span class="comment">// It would be really nice to teach stl to do this.</span>

<span class="keyword">class </span>ts_list_head {
<span class="keyword">public</span>:

        <span class="comment">// No point inheriting, I&#39;d have to implement</span>
        <span class="comment">// alot of code. We&#39;ll hold off on that exercise.</span>

        <span class="comment">// Using the CommonC++ Mutex class.</span>
        <a name="_a0"></a><a class="code" href="classost_1_1_mutex.html" title="The Mutex class is used to protect a section of code so that at any given time only...">Mutex</a>               linkmutex;
        <span class="comment">// And the STL template.</span>
        ts_list             list_o_items;

        <span class="comment">// Not nessasary, but nice to be explicit.</span>
        ts_list_head()
        : linkmutex(), list_o_items() {
        }

        <span class="comment">// This thing knows how to remove and insert items.</span>
        <span class="keywordtype">void</span> RemoveListItem( ts_list_item * li );
        <span class="keywordtype">void</span> InsertListItem( ts_list_item * li );

        <span class="comment">// And it knows how to notify that it became empty</span>
        <span class="comment">// or an element was deleted and it was the last one.</span>
        <span class="keyword">virtual</span> <span class="keywordtype">void</span> ListDepleted() {
        }

        <span class="keyword">virtual</span> ~ts_list_head() {
        }
};


<span class="comment">// This item knows how to remove itself from the</span>
<span class="comment">// list it belongs to.</span>
<span class="keyword">class </span>ts_list_item {
<span class="keyword">public</span>:
        ts_list::iterator          linkpoint;
        ts_list_head      * listhead;

        <span class="keyword">virtual</span> ~ts_list_item() {
        listhead-&gt;RemoveListItem( <span class="keyword">this</span> );
        }

        ts_list_item( ts_list_head * head ) {
        listhead = head;
        head-&gt;InsertListItem( <span class="keyword">this</span> );
        }
};

<span class="keywordtype">void</span> ts_list_head::RemoveListItem( ts_list_item * li )
{
        <span class="keywordtype">bool</span>    is_empty;
        linkmutex.enterMutex();
        list_o_items.erase( li-&gt;linkpoint );
        is_empty = list_o_items.empty();
        linkmutex.leaveMutex();

        <span class="comment">// There is a slim possibility that at this time</span>
        <span class="comment">// we recieve a connection.</span>
        <span class="keywordflow">if</span> ( is_empty ) {
        ListDepleted();
        }
}

<span class="keywordtype">void</span> ts_list_head::InsertListItem( ts_list_item * li )
{
        linkmutex.enterMutex();
        list_o_items.push_front( li );
        li-&gt;linkpoint = list_o_items.begin();
        linkmutex.leaveMutex();
}

<span class="comment">// ChatterSession operates on the individual connections</span>
<span class="comment">// from clients as are managed by the SocketService</span>
<span class="comment">// contained in CCExec.  ChatterThread simply waits in</span>
<span class="comment">// a loop to create these, listening forever.</span>
<span class="comment">//</span>
<span class="comment">// Even though the SocketService contains a list of</span>
<span class="comment">// clients it serves, it may actually serve more than</span>
<span class="comment">// one type of session so we create our own list by</span>
<span class="comment">// inheriting the ts_list_item.</span>
<span class="comment">//</span>

<span class="keyword">class </span>ChatterSession :
        <span class="keyword">public</span> <span class="keyword">virtual</span> <a name="_a1"></a><a class="code" href="classost_1_1_socket_port.html" title="The socket port is an internal class which is attached to and then serviced by a...">SocketPort</a>,
        <span class="keyword">public</span> <span class="keyword">virtual</span> ts_list_item {
<span class="keyword">public</span>:

        <span class="keyword">enum</span> { size_o_buf = 2048 };

        <span class="comment">// Nothing special to do here, it&#39;s all handled</span>
        <span class="comment">// by SocketPort and ts_list_item</span>

        <span class="keyword">virtual</span> ~ChatterSession() {
        cerr &lt;&lt; <span class="stringliteral">&quot;ChatterSession deleted !\n&quot;</span>;
        }

        <span class="comment">// When you create a ChatterSession it waits to accept a</span>
        <span class="comment">// connection.  This is done by it&#39;s own</span>
        ChatterSession(
        <a name="_a2"></a><a class="code" href="classost_1_1_t_c_p_socket.html" title="TCP sockets are used for stream based connected sessions between two sockets.">TCPSocket</a>      &amp; server,
        <a name="_a3"></a><a class="code" href="classost_1_1_socket_service.html" title="The SocketService is a thread pool object that is meant to service attached socket...">SocketService</a>   * svc,
        ts_list_head    * head
        ) :
        <a class="code" href="classost_1_1_socket_port.html" title="The socket port is an internal class which is attached to and then serviced by a...">SocketPort</a>( NULL, server ),
        ts_list_item( head ) {
        cerr &lt;&lt; <span class="stringliteral">&quot;ChatterSession Created\n&quot;</span>;

        <a name="a4"></a><a class="code" href="namespaceost.html#a3c74a1a40c359fd349f3e3e1b96ebfc7" title="Transport Protocol Ports.">tpport_t</a> port;
        <a name="a5"></a><a class="code" href="address_8h.html#a5eba36aa908d5a479c8ba7d0bc4512b1">InetHostAddress</a> ia = <a name="a6"></a><a class="code" href="classost_1_1_socket.html#a6fd1dffdfe9606e56fba838559ff6d67">getPeer</a>( &amp; port );

        cerr &lt;&lt; <span class="stringliteral">&quot;connecting from &quot;</span> &lt;&lt; ia.getHostname() &lt;&lt;
        <span class="stringliteral">&quot;:&quot;</span> &lt;&lt; port &lt;&lt; endl;

        <span class="comment">// Set up non-blocking reads</span>
        <a name="a7"></a><a class="code" href="classost_1_1_socket.html#a16eb72794ce956b2af6b935eb59b2e24" title="Used to specify blocking mode for the socket.">setCompletion</a>( <span class="keyword">false</span> );

        <span class="comment">// Set yerself to time out in 10 seconds</span>
        <a name="a8"></a><a class="code" href="classost_1_1_socket_port.html#ac70f9eae6b6b3625c980fa84180e8151" title="Derived setTimer to notify the service thread pool of change in expected timeout...">setTimer</a>( 100000 );
        <a name="a9"></a><a class="code" href="classost_1_1_socket_port.html#aed5fbff0b874da8e24add7f6cc50b65e" title="Attach yourself to the service pool thread object.">attach</a>(svc);
        }

        <span class="comment">//</span>
        <span class="comment">// This is called by the SocketService thread when it the</span>
        <span class="comment">// object has expired.</span>
        <span class="comment">//</span>

        <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a name="a10"></a><a class="code" href="classost_1_1_socket_port.html#a4d09daed3fe5cb81259985db87add34d" title="Called by the service thread pool when the objects timer has expired.">expired</a>() {
        <span class="comment">// Get outa here - this guy is a LOOSER - type or terminate</span>
        cerr &lt;&lt; <span class="stringliteral">&quot;ChatterSession Expired\n&quot;</span>;
        <span class="keyword">delete</span> <span class="keyword">this</span>;
        }

        <span class="comment">//</span>
        <span class="comment">// This is called by the SocketService thread when it detects</span>
        <span class="comment">// that there is somthing to read on this connection.</span>
        <span class="comment">//</span>

        <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a name="a11"></a><a class="code" href="classost_1_1_socket_port.html#a5e0ec242cfb737db369cbc63abcc06b6" title="Called by the service thread pool when input data is pending for this socket.">pending</a>() {
        <span class="comment">// Implement the echo</span>

        cerr &lt;&lt; <span class="stringliteral">&quot;Pending called\n&quot;</span>;

        <span class="comment">// reset the timer</span>
        <a class="code" href="classost_1_1_socket_port.html#ac70f9eae6b6b3625c980fa84180e8151" title="Derived setTimer to notify the service thread pool of change in expected timeout...">setTimer</a>( 100000 );
        <span class="keywordflow">try</span> {
            <span class="keywordtype">int</span>    len;
            <span class="keywordtype">unsigned</span> <span class="keywordtype">int</span> total = 0;
            <span class="keywordtype">char</span>    buf[ size_o_buf ];

            <span class="keywordflow">while</span> ( (len = <a name="a12"></a><a class="code" href="classost_1_1_socket_port.html#a872c38a65b17113a580af345946146d7" title="Receive a message from any host.">receive</a>(buf, <span class="keyword">sizeof</span>(buf) )) &gt; 0 ) {
                total += len;
                cerr &lt;&lt; <span class="stringliteral">&quot;Read &#39;&quot;</span>;
                cerr.write( buf, len );
                cerr &lt;&lt; <span class="stringliteral">&quot;&#39;\n&quot;</span>;

                <span class="comment">// Send it to all the sessions.</span>
                <span class="comment">// We probably don&#39;t really want to lock the</span>
                <span class="comment">// entire list for the entire time.</span>
                <span class="comment">// The best way to do this would be to place the</span>
                <span class="comment">// message somewhere and use the service function.</span>
                <span class="comment">// But what are examples for ?</span>

                <span class="keywordtype">bool</span> sent = <span class="keyword">false</span>;
                listhead-&gt;linkmutex.enterMutex();
                <span class="keywordflow">for</span> (
                   ts_list::iterator iter = listhead-&gt;list_o_items.begin();
                   iter != listhead-&gt;list_o_items.end();
                   iter ++
                ) {
                   ChatterSession * sess =
                    <span class="keyword">dynamic_cast&lt;</span> ChatterSession * <span class="keyword">&gt;</span>( * iter );
                   <span class="keywordflow">if</span> ( sess != <span class="keyword">this</span> ) {
                    sess-&gt;send( buf, len );
                    sent = <span class="keyword">true</span>;
                   }
                }
                listhead-&gt;linkmutex.leaveMutex();

                <span class="keywordflow">if</span> ( ! sent ) {
                   <a name="a13"></a><a class="code" href="classost_1_1_socket_port.html#a9218e4528f5bdf4215200e2040eefe5b" title="Transmit &amp;quot;send&amp;quot; data to a connected peer host.">send</a>(
                    ( <span class="keywordtype">void</span> * ) <span class="stringliteral">&quot;No one else listening\n&quot;</span>,
                    <span class="keyword">sizeof</span>( <span class="stringliteral">&quot;No one else listening\n&quot;</span> ) - 1
                   );

                   <a class="code" href="classost_1_1_socket_port.html#a9218e4528f5bdf4215200e2040eefe5b" title="Transmit &amp;quot;send&amp;quot; data to a connected peer host.">send</a>( buf, len );
                }
            }
            <span class="keywordflow">if</span> (total == 0) {
                cerr &lt;&lt; <span class="stringliteral">&quot;Broken connection!\n&quot;</span> &lt;&lt; endl;
                <span class="keyword">delete</span> <span class="keyword">this</span>;
            }
        }
        <span class="keywordflow">catch</span> ( ... ) {
            <span class="comment">// somthing wrong happened here !</span>
            cerr &lt;&lt; <span class="stringliteral">&quot;Socket port write sent an exception !\n&quot;</span>;
        }

        }

        <span class="keyword">virtual</span> <span class="keywordtype">void</span> <a name="a14"></a><a class="code" href="classost_1_1_socket_port.html#a7b2a739ee0cb11bc6332010f4cd21552" title="Called by the service thread pool when a disconnect has occured.">disconnect</a>() {
        <span class="comment">// Called by the SocketService thread when the client</span>
        <span class="comment">// hangs up.</span>
        cerr &lt;&lt; <span class="stringliteral">&quot;ChatterSession disconnected!\n&quot;</span>;

        <span class="keyword">delete</span> <span class="keyword">this</span>;
        }

};

<span class="keyword">class </span>ChatterThread;

<span class="comment">//</span>
<span class="comment">// This is the main application object containing all the</span>
<span class="comment">// state for the application.  It uses a SocketService object</span>
<span class="comment">// (and thread) to do all the work, however, that object could</span>
<span class="comment">// theoretically be use by more than one main application.</span>
<span class="comment">//</span>
<span class="comment">// It creates a ChatterThread to sit and wait for connections</span>
<span class="comment">// from clients.</span>

<span class="keyword">class </span>CCExec : <span class="keyword">public</span> <span class="keyword">virtual</span> ts_list_head {
<span class="keyword">public</span>:

        <a class="code" href="classost_1_1_socket_service.html" title="The SocketService is a thread pool object that is meant to service attached socket...">SocketService</a>       * service;
        ChatterThread          * my_Chatter;
        <a name="_a15"></a><a class="code" href="classost_1_1_semaphore.html" title="A semaphore is generally used as a synchronization object between multiple threads...">Semaphore</a>                     mainsem[1];

        CCExec():my_Chatter(NULL) {
        service = <span class="keyword">new</span> <a class="code" href="classost_1_1_socket_service.html" title="The SocketService is a thread pool object that is meant to service attached socket...">SocketService</a>( 0 );
        }

        <span class="keyword">virtual</span> <span class="keywordtype">void</span> ListDepleted();

        <span class="comment">// These methods defined later.</span>
        <span class="keyword">virtual</span> ~CCExec();
        <span class="keywordtype">int</span> RunApp( <span class="keywordtype">char</span> * hn = (<span class="keywordtype">char</span> *)<span class="stringliteral">&quot;localhost&quot;</span> );

};

<span class="comment">//</span>
<span class="comment">// ChatterThread simply creates ChatterSession all the time until</span>
<span class="comment">// it has an error.  I suspect you could create as many of these</span>
<span class="comment">// as the OS could take.</span>
<span class="comment">//</span>

<span class="keyword">class </span>ChatterThread : <span class="keyword">public</span> <span class="keyword">virtual</span> <a class="code" href="classost_1_1_t_c_p_socket.html" title="TCP sockets are used for stream based connected sessions between two sockets.">TCPSocket</a>, <span class="keyword">public</span> <span class="keyword">virtual</span> <a name="_a16"></a><a class="code" href="classost_1_1_thread.html" title="Every thread of execution in an application is created by instantiating an object...">Thread</a> {
<span class="keyword">public</span>:

        CCExec          * exec;

        <span class="keywordtype">void</span> <a name="a17"></a><a class="code" href="classost_1_1_thread.html#add7d339d94b8a1ed2b2b0324a95b7e74" title="All threads execute by deriving the Run method of Thread.">run</a> () {
        <span class="keywordflow">while</span> ( 1 ) {
            <span class="keywordflow">try</span> {
                <span class="comment">// new does all the work to accept a new connection</span>
                <span class="comment">// attach itself to the SocketService AND include</span>
                <span class="comment">// itself in the CCExec list of sessions.</span>
                <span class="keyword">new</span> ChatterSession(
                   * ( <a class="code" href="classost_1_1_t_c_p_socket.html" title="TCP sockets are used for stream based connected sessions between two sockets.">TCPSocket</a> * ) <span class="keyword">this</span>,
                   exec-&gt;service,
                   exec
                );
            }
            <span class="keywordflow">catch</span> ( ... ) {
                <span class="comment">// Bummer - there was an error.</span>
                cerr &lt;&lt; <span class="stringliteral">&quot;ChatterSession create failed\n&quot;</span>;
                <a name="a18"></a><a class="code" href="classost_1_1_thread.html#acd315d7c877b346970680d739da3e994" title="Used to properly exit from a Thread derived run() or initial() method.">exit</a>();
            }
        }
        }

        ChatterThread(
        <a class="code" href="address_8h.html#a5eba36aa908d5a479c8ba7d0bc4512b1">InetHostAddress</a> &amp; machine,
        <span class="keywordtype">int</span>           port,
        CCExec         * inexec

        ) : <a class="code" href="classost_1_1_t_c_p_socket.html" title="TCP sockets are used for stream based connected sessions between two sockets.">TCPSocket</a>( machine, port ),
        <a class="code" href="classost_1_1_thread.html" title="Every thread of execution in an application is created by instantiating an object...">Thread</a>(),
        exec( inexec ) {
            <a name="a19"></a><a class="code" href="classost_1_1_thread.html#a2ef198d7aefb93cf9de4fcc6b66c27a2" title="When a new thread is created, it does not begin immediate execution.">start</a>();
        }


};

<span class="comment">//</span>
<span class="comment">// Bug here, this should go ahead and shut down all sessions</span>
<span class="comment">// for application.  An exercise left to the reader.</span>

CCExec::~CCExec()
{
        <span class="comment">// MUST delete my_Chatter first or it may end up using</span>
        <span class="comment">// a deleted service.</span>
        <span class="keywordflow">if</span> ( my_Chatter ) <span class="keyword">delete</span> my_Chatter;

        <span class="comment">// Delete whatever is left.</span>
        <span class="keyword">delete</span> service;
}

<span class="comment">//</span>
<span class="comment">// Run App would normally read some config file or take some</span>
<span class="comment">// parameters about which port to connect to and then</span>
<span class="comment">// do that !</span>
<span class="keywordtype">int</span> CCExec::RunApp( <span class="keywordtype">char</span> * hn )
{
        <span class="comment">// which port ?</span>

        <a class="code" href="address_8h.html#a5eba36aa908d5a479c8ba7d0bc4512b1">InetHostAddress</a> machine( hn );

        <span class="keywordflow">if</span> ( machine.isInetAddress() == false ) {
        cerr &lt;&lt; <span class="stringliteral">&quot;machine is not address&quot;</span> &lt;&lt; endl;
        }

        cerr &lt;&lt; <span class="stringliteral">&quot;machine is &quot;</span> &lt;&lt; machine.getHostname() &lt;&lt; endl;

        <span class="comment">// Start accepting connections - this will bind to the</span>
        <span class="comment">// port as well.</span>
        <span class="keywordflow">try</span> {
        my_Chatter = <span class="keyword">new</span> ChatterThread(
            machine,
            3999,
            <span class="keyword">this</span>
        );
        }
        <span class="keywordflow">catch</span> ( ... ) {
        cerr &lt;&lt; <span class="stringliteral">&quot;Failed to bind\n&quot;</span>;
        <span class="keywordflow">return</span> <span class="keyword">false</span>;
        }

        <span class="keywordflow">return</span> <span class="keyword">true</span>;
}

<span class="comment">// When there is no one else connected - terminate !</span>
<span class="keywordtype">void</span> CCExec::ListDepleted()
{
        mainsem-&gt;post();
}


<span class="keywordtype">int</span> main( <span class="keywordtype">int</span> argc, <span class="keywordtype">char</span> ** argv )
{
        CCExec  * server;

        server = <span class="keyword">new</span> CCExec();

        <span class="comment">// take the first command line option as a hostname</span>
        <span class="comment">// to listen to.</span>
        <span class="keywordflow">if</span> ( argc &gt; 1 ) {
                server-&gt;RunApp( argv[ 1 ] );
        } <span class="keywordflow">else</span> {
                server-&gt;RunApp();
        }

        server-&gt;mainsem-&gt;wait();

        <span class="keyword">delete</span> server;

        <span class="keywordflow">return</span> 0;
}
</pre></div> </div>
<hr class="footer"/><address style="text-align: right;"><small>Generated on Fri Nov 12 09:55:46 2010 for GNU CommonC++ by&nbsp;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.6.3 </small></address>
</body>
</html>