summaryrefslogtreecommitdiff
path: root/docs/tutorials/008
diff options
context:
space:
mode:
authorjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-09-05 21:05:04 +0000
committerjcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-09-05 21:05:04 +0000
commitef1a88ade3bbde1f660baceb470135cd920e0b53 (patch)
treeee33bff80057b1b4ca600b5ae9a4d8aa61a3787f /docs/tutorials/008
parentaed7cb18ee0d109023ab548231219adff8e2281a (diff)
downloadATCD-ef1a88ade3bbde1f660baceb470135cd920e0b53.tar.gz
Datagram tutorials begun
Diffstat (limited to 'docs/tutorials/008')
-rw-r--r--docs/tutorials/008/Makefile63
-rw-r--r--docs/tutorials/008/broadcast_client.cpp72
-rw-r--r--docs/tutorials/008/directed_client.cpp112
-rw-r--r--docs/tutorials/008/page01.html60
-rw-r--r--docs/tutorials/008/page02.html237
-rw-r--r--docs/tutorials/008/page03.html187
-rw-r--r--docs/tutorials/008/page04.html156
-rw-r--r--docs/tutorials/008/page05.html43
-rw-r--r--docs/tutorials/008/server.cpp128
9 files changed, 1058 insertions, 0 deletions
diff --git a/docs/tutorials/008/Makefile b/docs/tutorials/008/Makefile
new file mode 100644
index 00000000000..59ac6bca63f
--- /dev/null
+++ b/docs/tutorials/008/Makefile
@@ -0,0 +1,63 @@
+#----------------------------------------------------------------------------
+# $Id$
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+BIN = server directed_client broadcast_client
+
+FILES =
+
+BUILD = $(VBIN)
+
+# SRC = $(addsuffix .cpp,$(BIN)) $(addsuffix .cpp,$(FILES))
+
+HDR = *.h
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(ACE_ROOT)/include/makeinclude/macros.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.common.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.lib.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+Indent : #
+ for i in $(SRC) $(HDR) ; do \
+ indent -npsl -l80 -fca -fc1 -cli0 -cdb < $$i | \
+ sed -e 's/: :/::/g' \
+ -e 's/^.*\(public:\)/\1/' \
+ -e 's/^.*\(protected:\)/\1/' \
+ -e 's/^.*\(private:\)/\1/' \
+ -e 's/:\(public\)/ : \1/' \
+ -e 's/:\(protected\)/ : \1/' \
+ -e 's/:\(private\)/ : \1/' \
+ > $$i~ ;\
+ mv $$i~ $$i ;\
+ done
+
+Depend : depend
+ perl ../fix.Makefile
+
+.depend : #
+ touch .depend
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+ # Don't put anything below here. Between the "depend" target and fix.Makefile
+ # it's guaranteed to be lost!
+
+ # This is inserted by the fix.Makefile script
+include .depend
diff --git a/docs/tutorials/008/broadcast_client.cpp b/docs/tutorials/008/broadcast_client.cpp
new file mode 100644
index 00000000000..2f754806d03
--- /dev/null
+++ b/docs/tutorials/008/broadcast_client.cpp
@@ -0,0 +1,72 @@
+
+// $Id$
+
+#include "ace/SOCK_Dgram_Bcast.h"
+#include "ace/INET_Addr.h"
+
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main(int argc,char *argv[] )
+{
+ ACE_INET_Addr local((u_short)0);
+
+ /*
+ Instead of creating the ACE_SOCK_Dgram we created last time,
+ we'll create an ACE_SOCK_Dgram_Bcast. "Bcast" means, of course,
+ "Broadcast". This ACE object is clever enough to go out to the
+ OS and find all of the network interfaces. When you send()
+ on a Dgram_Bcast, it will send the datagram out on all of those
+ interfaces. This is quiet handy if you do it on a multi-homed
+ host that plays router...
+ */
+ ACE_SOCK_Dgram_Bcast dgram;
+
+ if( dgram.open(local) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1);
+ }
+
+ char buf[512];
+
+ sprintf(buf, "Hello World!");
+
+ /*
+ The only other difference between us and the directed client
+ is that we don't specify a host to receive the datagram.
+ Instead, we use the magic value "INADDR_BROADCAST". All hosts
+ are obliged to respond to datagrams directed to this address
+ the same as they would to datagrams sent to their hostname.
+
+ Remember, the Dgram_Bcast will send a datagram to all interfaces
+ on the host. That's true even if the address is for a specific
+ host (and the host address makes sense for the interface).
+ The real power is in using an INADDR_BROADCAST addressed datagram
+ against all interfaces.
+ */
+
+ ACE_INET_Addr remote(PORT,INADDR_BROADCAST);
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) Sending (%s) to the server.\n",buf));
+
+ if( dgram.send(buf,strlen(buf)+1,remote) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);
+ }
+
+ if( dgram.recv(buf,sizeof(buf),remote) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server said: %s\n",buf));
+
+ /*
+ Using the "remote" object instance, find out where the server lives.
+ We could then save this address and use directed datagrams to chat
+ with the server for a while.
+ */
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server can be found at: (%s:%d)\n",
+ remote.get_host_name(), PORT ));
+
+ return(0);
+}
diff --git a/docs/tutorials/008/directed_client.cpp b/docs/tutorials/008/directed_client.cpp
new file mode 100644
index 00000000000..7fac216dbc3
--- /dev/null
+++ b/docs/tutorials/008/directed_client.cpp
@@ -0,0 +1,112 @@
+
+// $Id$
+
+#include "ace/SOCK_Dgram.h"
+#include "ace/INET_Addr.h"
+
+/*
+ Once again, we use the default server port. In a "real" system,
+ the server's port (or ports) would be published in some way so
+ that clients would know where to "look". We could even add entries
+ to the operating system's services file and use a service name
+ instead of a number. We'll come back to that in some other tutorial
+ though. For now, let's stay simple.
+ */
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+/*
+ Our goal here is to develop a client that can send a datagram to
+ a server running on a known host. We'll use a command-line argument
+ to specify the hostname instead of hard-coding it.
+ */
+int main(int argc,char *argv[] )
+{
+ /*
+ All datagrams have to have a point of origin. Since we intend to
+ transmit instead of receive, we initialize an address with zero
+ and let the OS choose a port for us. We could have chosen our
+ own value between 1025 and 65535 as long as it isn't already in use.
+ */
+ ACE_INET_Addr local((u_short)0);
+
+ /*
+ And here is our datagram object.
+ */
+ ACE_SOCK_Dgram dgram;
+
+ /*
+ Notice that this looks a lot like the server application. There's
+ no difference in creating server datagrams an client datagrams.
+ You can even use a zero-constructed address for your server datagram
+ as long as you tell the client where you're listening (eg -- by writting
+ into a file or some such).
+ */
+ if( dgram.open(local) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1);
+ }
+
+ /*
+ Yep. We've seen this before too...
+ */
+ char buf[512];
+
+ /*
+ Ok, now we're doing something different.
+ */
+ sprintf(buf, "Hello World!");
+
+ /*
+ Just like sending a telegram, we have to address our datagram.
+ Here, we create an address object at the desired port on the
+ chosen host. To keep us from crashing, we'll provide a default
+ host name if we aren't given one.
+ */
+ ACE_INET_Addr remote(PORT, argc > 1 ? argv[1] : "localhost" );
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) Sending (%s) to the server.\n",buf));
+ /*
+ Now we send our buffer of stuff to the remote address. This is
+ just exactly what the server did after receiving a client message.
+ Datagrams are rather orthogonal that way: they don't generally make
+ much of a fuss about being either client or server.
+ */
+ if( dgram.send(buf,strlen(buf)+1,remote) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);
+ }
+
+ /*
+ Now we've turned around and put ourselves into "server mode" by
+ invoking the recv() method. We now our server is going to send
+ us something, so we hang out here and wait for it. Because we
+ know datagrams are unreliable, there is a chance that the server
+ will respond but we won't hear. You might consider providing a
+ timeout on the recv() in that case. If recv() fails due to timeout
+ it will return -1 and you can then resend your query and attempt
+ the recv() again.
+
+ Like the server application, we have to give the recv() an
+ uninitialized addr object so that we can find out who is talking
+ back to us.
+ */
+ if( dgram.recv(buf,sizeof(buf),remote) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1);
+ }
+
+ /*
+ Find out what the server had to say.
+ */
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server said: %s\n",buf));
+
+ /*
+ Using the "remote" object instance, find out where the server lives.
+ We could then save this address and use directed datagrams to chat
+ with the server for a while.
+ */
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) The server can be found at: (%s:%d)\n",
+ remote.get_host_name(), PORT ));
+
+ return(0);
+}
diff --git a/docs/tutorials/008/page01.html b/docs/tutorials/008/page01.html
new file mode 100644
index 00000000000..ebe24e9ecc8
--- /dev/null
+++ b/docs/tutorials/008/page01.html
@@ -0,0 +1,60 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; I; Linux 2.0.32 i486) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 008</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+
+<P>In a lot of IPC&nbsp;programming, the clients know where the servers
+are.&nbsp; A mail client, for instance, has a configuration file that says
+where the mail host is.&nbsp; Your web browser has a "location" field that
+you type into to give it a destination.
+
+<P>What if you have written a server application and then you execute it
+on several systems in your network?&nbsp; All of the instances are probably
+more or less equal to the client's point of view, so you don't want to
+"configure"&nbsp;the clients to a single server each.&nbsp; Likewise, you
+want the ability to add and remove servers at any time so you can't just
+give the clients a list to choose from.
+
+<P>So... how do the clients know where the servers are?
+
+<P>Let 'em ask!
+
+<P>Datagrams are great for this.&nbsp; You can toss a datagram out onto
+the network and any servers listening at the correct port will* hear it.&nbsp;
+Like ACE_SOCK_Stream that we've seen before, you can get the peer address
+from a datagram.&nbsp; With that, the server can&nbsp; send a response
+back to the client.&nbsp; The client, in turn, can pull the peer address
+out and know exactly where the server lives.
+
+<P>In this tutorial we'll develop three applications:&nbsp; a server listening
+for datagrams, a client that can send to a known host and a client that
+can send to the entire (sub)network.&nbsp; In the next tutorial, we'll
+expand on this to make the server a bit more prudish.
+<BR>&nbsp;
+
+<P><FONT SIZE=-1>*&nbsp;Actually, the servers <I>might</I> hear the datagram.&nbsp;
+Datagrams are rather unreliable.&nbsp; (Sort of like some operating systems
+I know.)&nbsp; Still, if the network traffic isn't too bad, they generally
+get through.&nbsp; Your clients can always send out more queries if there
+aren't any responses in a timely fashion.</FONT>
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="..">Tutorial
+Index</A>] [<A HREF="page02.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/008/page02.html b/docs/tutorials/008/page02.html
new file mode 100644
index 00000000000..25a47e7e4f5
--- /dev/null
+++ b/docs/tutorials/008/page02.html
@@ -0,0 +1,237 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 008</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+
+<P>The first thing we want to look at is <A HREF="server.cpp">server.cpp</A>.&nbsp;
+This is a pretty simple application that listens for datagrams at a known
+port and sends back a response.&nbsp; In order to implement a true "discovery"&nbsp;
+mechanism, the server will have to be a little bit more picky about who
+it responds to.&nbsp; We'll tackle that issue in the next tutorial though...
+
+<P>
+<HR WIDTH="100%">
+
+<P><TT>/*</TT>
+<BR><TT>&nbsp;&nbsp; Our datagram server will, of course, need to create
+a datagram.</TT>
+<BR><TT>&nbsp;&nbsp; We'll also need an address object so that we know
+where to listen.</TT>
+<BR><TT>&nbsp;*/</TT>
+<BR><TT>#include "ace/SOCK_Dgram.h"</TT>
+<BR><TT>#include "ace/INET_Addr.h"</TT>
+
+<P><TT>/*</TT>
+<BR><TT>&nbsp;&nbsp; Use the typical TCP/IP port address for receiving
+datagrams.</TT>
+<BR><TT>&nbsp;*/</TT>
+<BR><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT>
+
+<P><TT>int main(int,char**)</TT>
+<BR><TT>{</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; This is where we'll listen
+for datagrams coming from the</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clients.&nbsp; We'll give
+this address to the open() method</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; below to enable the listener.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp; ACE_INET_Addr&nbsp; local(PORT);</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A simply constructed datagram
+that we'll listen with.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp; ACE_SOCK_Dgram dgram;</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Like most ACE objects, the
+datagram has to be opened before</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; it can be uses.&nbsp; Of course,
+-1 on failure.</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A datagram will fail to open
+if there is already a datagram</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; listening at the port we've
+chosen.&nbsp; It *is* OK to open</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a datagram at a port where
+there is an ACE_SOCK_Stream</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; though.&nbsp; This is because
+datagrams are UDP and SOCK_Stream</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is TCP and the two don't cross
+paths.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp; if( dgram.open(local) == -1 )</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp; {</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_ERROR_RETURN ((LM_ERROR,
+"%p\n", "open"),-1);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp; }</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Create a simple buffer to
+receive the data.&nbsp; You generally need</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to provide a buffer big enough
+for the largest datagram you</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expect to receive.&nbsp; Some
+platforms will let you read a little</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and then some more later but
+other platforms will throw out</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; whatever part of the datagram
+you don't get with the first</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; read.&nbsp; (This is on a
+per-datagram basis BTW.)&nbsp; The theoretical</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; limit on a datagram is about
+64k.&nbsp; The realistic limit (because</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; of routers &amp; such) is
+much smaller.&nbsp; Choose your buffer size</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; based on your application's
+needs.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp; char buf[512];</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Unlike ACE_SOCK_Stream, datagrams
+are unconnected.&nbsp; That is,</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; there is no "virtual circuit"
+between server and client.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Because of this, the server
+has to provide a placeholder</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for the OS to fill in the
+source (client) address information</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; on the recv.&nbsp; You can
+initialize this INET_Addr to anything,</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; it will be overwritten when
+the data arrives.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp; ACE_INET_Addr remote;</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp; ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server
+daemon\n"));</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Receive datagrams as long
+as we're able.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp; while( dgram.recv(buf,sizeof(buf),remote) !=
+-1 )</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp; {</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Display
+a brief message about our progress.&nbsp; Notice how we</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; use
+the 'remote' object to display the address of the client.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; With
+an ACE_SOCK_Stream we used get_remote_addr() to get the</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; address
+the socket is connected to.&nbsp; Because datagrams are</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unconnected,
+we use the addr object provided to recv().</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_DEBUG ((LM_DEBUG,
+"(%P|%t) Data (%s) from client (%s)\n", buf, remote.get_host_name()));</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; To
+respond to the client's query, we have to become a client</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ourselves.&nbsp;
+To do so, we need an anonymous local address from</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; which
+we'll send the response and a datagram in which to send</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; it.&nbsp;
+(An anonymous address is simply one where we let the OS</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; choose
+a port for us.&nbsp; We really don't care what it is.O</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_INET_Addr&nbsp;
+local((u_short)0);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_SOCK_Dgram client;</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Open
+up our response datagram as always.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( client.open(local)
+== -1 )</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "client open"),-1);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return(0);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Build
+a witty response...</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(buf,"I am here");</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and
+send it to the client.&nbsp; Notice the symetry with the recv()</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; method.&nbsp;
+Again, the unconnected nature of datagrams forces</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; us
+to specify an address object with each read/write operation.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; In
+the case of read (recv()) that's where the OS stuffs the</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; address
+of the datagram sender.&nbsp; In the case of write (send())</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; that
+we're doing here, the address is where we want the network</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to
+deliver the data.</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Of
+course, we're assuming that the client will be listening</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for
+our reply...</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( client.send(buf,strlen(buf)+1,remote)
+== -1 )</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+return(0);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp; }</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp; return(0);</TT>
+<BR><TT>}</TT>
+
+<P>
+<HR WIDTH="100%">
+
+<P>And that's really all there is to it.&nbsp; Obviously there is some
+room for improvement.&nbsp; The most blatant is the somewhat small buffer
+size for receiving the datagram.&nbsp; I've never been able to get a solid
+answer on datagram sizes.&nbsp; The theoretical limit is just under 64k
+but you have to deal with fragmentation.&nbsp; Some readings indicate that
+8k is a reasonable size, others go much smaller.&nbsp; My general rule
+of thumb is to keep datagrams relatively small (eg -- under 8k or so) and
+test a lot.&nbsp; If you find that your routers are fragmenting your larger
+datagrams, back off to something smaller.&nbsp; Of course, if you must
+send 100k and can only do so 1k at a time, you'll have to worry about retransmissions
+&amp; reordering.&nbsp; At that point, you might consider going to TCP.&nbsp;
+Remember:&nbsp; datagrams are unreliable!&nbsp; Don't try to make 'em do
+something they werent' designed for!
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="../../tutorials">Tutorial Index</A>] [<A HREF="page03.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/008/page03.html b/docs/tutorials/008/page03.html
new file mode 100644
index 00000000000..c572eaf622f
--- /dev/null
+++ b/docs/tutorials/008/page03.html
@@ -0,0 +1,187 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 008</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+
+<P>In <A HREF="directed_client.cpp">directed_client.cpp</A> we create a
+client that knows how to send a datagram to a server on a known host.&nbsp;
+This is a good thing if you know where the server lives and want to have
+a conversation.&nbsp;&nbsp; The Unix <I>talk</I> utilitiy, for instance,
+could be written this way.
+
+<P>
+<HR WIDTH="100%">
+
+<P><TT>#include "ace/SOCK_Dgram.h"</TT>
+<BR><TT>#include "ace/INET_Addr.h"</TT>
+
+<P><TT>/*</TT>
+<BR><TT>&nbsp;&nbsp; Once again, we use the default server port.&nbsp;
+In a "real" system,</TT>
+<BR><TT>&nbsp;&nbsp; the server's port (or ports) would be published in
+some way so</TT>
+<BR><TT>&nbsp;&nbsp; that clients would know where to "look".&nbsp; We
+could even add entries</TT>
+<BR><TT>&nbsp;&nbsp; to the operating system's services file and use a
+service name</TT>
+<BR><TT>&nbsp;&nbsp; instead of a number.&nbsp; We'll come back to that
+in some other tutorial</TT>
+<BR><TT>&nbsp;&nbsp; though.&nbsp; For now, let's stay simple.</TT>
+<BR><TT>&nbsp;*/</TT>
+<BR><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT>
+
+<P><TT>/*</TT>
+<BR><TT>&nbsp;&nbsp; Our goal here is to develop a client that can send
+a datagram to</TT>
+<BR><TT>&nbsp;&nbsp; a server running on a known host.&nbsp; We'll use
+a command-line argument</TT>
+<BR><TT>&nbsp;&nbsp; to specify the hostname instead of hard-coding it.</TT>
+<BR><TT>&nbsp;*/</TT>
+<BR><TT>int main(int argc,char *argv[] )</TT>
+<BR><TT>{</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; All
+datagrams have to have a point of origin.&nbsp; Since we intend to</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transmit
+instead of receive, we initialize an address with zero</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; and
+let the OS choose a port for us.&nbsp; We could have chosen our</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; own
+value between 1025 and 65535 as long as it isn't already in use.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_INET_Addr&nbsp;
+local((u_short)0);</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; And
+here is our datagram object.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_SOCK_Dgram dgram;</TT>
+<BR><TT>&nbsp;</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Notice
+that this looks a lot like the server application.&nbsp; There's</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; no
+difference in creating server datagrams an client datagrams.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; You
+can even use a zero-constructed address for your server datagram</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; as
+long as you tell the client where you're listening (eg -- by writting</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; into
+a file or some such).</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( dgram.open(local)
+== -1 )</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Yep.&nbsp;
+We've seen this before too...</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char buf[512];</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Ok,
+now we're doing something different.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(buf, "Hello
+World!");</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Just
+like sending a telegram, we have to address our datagram.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Here,
+we create an address object at the desired port on the</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chosen
+host.&nbsp; To keep us from crashing, we'll provide a default</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; host
+name if we aren't given one.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_INET_Addr&nbsp;
+remote(PORT, argc > 1 ? argv[1] : "localhost" );</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_DEBUG ((LM_DEBUG,
+"(%P|%t) Sending (%s) to the server.\n",buf));</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Now we send our buffer of stuff to the remote address.&nbsp; This is</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+just exactly what the server did after receiving a client message.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Datagrams are rather orthogonal that way:&nbsp; they don't generally make</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+much of a fuss about being either client or server.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( dgram.send(buf,strlen(buf)+1,remote)
+== -1 )</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Now
+we've turned around and put ourselves into "server mode" by</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; invoking
+the recv() method.&nbsp; We now our server is going to send</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; us
+something, so we hang out here and wait for it.&nbsp; Because we</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; know
+datagrams are unreliable, there is a chance that the server</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; will
+respond but we won't hear.&nbsp; You might consider providing a</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timeout
+on the recv() in that case.&nbsp; If recv() fails due to timeout</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; it
+will return -1 and you can then resend your query and attempt</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the
+recv() again.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( dgram.recv(buf,sizeof(buf),remote)
+== -1 )</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Find
+out what the server had to say.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_DEBUG ((LM_DEBUG,
+"(%P|%t) The server said:&nbsp; %s\n",buf));</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return(0);</TT>
+<BR><TT>}</TT>
+
+<P>
+<HR WIDTH="100%">
+
+<P>That's all neat and good but the point of what we're doing here is not
+to talk to a server we know about but to discover servers we don't know
+about.&nbsp; Now, you could send a directed datagram to every possible
+host address on your network but that's not a very nice thing to do.&nbsp;
+On the next page, we'll find out the right approach...
+
+<P>
+<HR WIDTH="100%">
+<CENTER>[<A HREF="../../tutorials">Tutorial Index</A>] [<A HREF="page04.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/008/page04.html b/docs/tutorials/008/page04.html
new file mode 100644
index 00000000000..8b6a65570ec
--- /dev/null
+++ b/docs/tutorials/008/page04.html
@@ -0,0 +1,156 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 008</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+<BR>&nbsp;
+<BR>&nbsp;In <A HREF="broadcast_client.cpp">broadcast_client.cpp</A> we
+find out how to send a single datagram to every host on our (sub)network.&nbsp;
+I have to say <I>(sub)network</I> because broadcast datagrams typically
+are not passed through routers.&nbsp; So, if your network admin has divided
+up your network into subnets, your broadcasts will likey only stay on the
+subnet you're a part of.
+
+<P>I've only commented the parts that are different from the directed_client.
+
+<P>
+<HR WIDTH="100%">
+
+<P><TT>#include "ace/SOCK_Dgram_Bcast.h"</TT>
+<BR><TT>#include "ace/INET_Addr.h"</TT>
+
+<P><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT>
+
+<P><TT>int main(int argc,char *argv[] )</TT>
+<BR><TT>{</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_INET_Addr&nbsp;
+local((u_short)0);</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Instead
+of creating the ACE_SOCK_Dgram we created last time,</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; we'll
+create an ACE_SOCK_Dgram_Bcast.&nbsp; "Bcast" means, of course,</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Broadcast".&nbsp;
+This ACE object is clever enough to go out to the</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OS
+and find all of the network interfaces.&nbsp; When you send()</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; on
+a Dgram_Bcast, it will send the datagram out on all of those</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; interfaces.&nbsp;
+This is quiet handy if you do it on a multi-homed</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; host
+that plays router...</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_SOCK_Dgram_Bcast
+dgram;</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( dgram.open(local)
+== -1 )</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char buf[512];</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sprintf(buf, "Hello World!");</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The
+only other difference between us and the directed client</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; is
+that we don't specify a host to receive the datagram.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Instead,
+we use the magic value "INADDR_BROADCAST".&nbsp; All hosts</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; are
+obliged to respond to datagrams directed to this address</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; the
+same as they would to datagrams sent to their hostname.</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Remember,
+the Dgram_Bcast will send a datagram to all interfaces</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; on
+the host.&nbsp; That's true even if the address is for a specific</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; host
+(and the host address makes sense for the interface).</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The
+real power is in using an INADDR_BROADCAST addressed datagram</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; against
+all interfaces.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_INET_Addr&nbsp;
+remote(PORT,INADDR_BROADCAST);</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_DEBUG ((LM_DEBUG,
+"(%P|%t) Sending (%s) to the server.\n",buf));</TT>
+<BR><TT>&nbsp;</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( dgram.send(buf,strlen(buf)+1,remote)
+== -1 )</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( dgram.recv(buf,sizeof(buf),remote)
+== -1 )</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1);</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_DEBUG ((LM_DEBUG,
+"(%P|%t) The server said:&nbsp; %s\n",buf));</TT>
+
+<P><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Using
+the <I>remote</I> object instance, find out where the server lives.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; We
+could then save this address and use directed datagrams to chat</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with
+the server for a while.</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ACE_DEBUG ((LM_DEBUG,
+"(%P|%t) The server can be found at:&nbsp; (%s:%d)\n",</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+remote.get_host_addr(), PORT ));</TT>
+<BR><TT>&nbsp;</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return(0);</TT>
+<BR><TT>}</TT>
+
+<P>
+<HR WIDTH="100%">
+
+<P>&nbsp;About that subnet thing:
+<BLOCKQUOTE>If you run this client on a host that has multiple network
+interfaces, the broadcast will go to all of those (sub)networks.&nbsp;
+What do you do, though, if you need to get past a router?&nbsp; My advice
+is to write a server that will run on hosts on both sides of your router.&nbsp;
+When a server on one side of the router receives a broadcast, it would
+send a directed datagram to it's counterpart on the other side of the router.&nbsp;
+The counterpart would then re-broadcast the original datagram on that sub-net.&nbsp;
+Cheap, simple and effective.</BLOCKQUOTE>
+One final word of warning:
+<BLOCKQUOTE>When creating your broadcast datagrams you may see something
+like this:&nbsp; <I>ACE_SOCK_Dgram_Bcast::mk_broadcast: Broadcast is not
+enable for this interface.: Unknown error</I>.&nbsp; There are some interfaces
+(ppp, slip) that don't support broadcast datagrams.&nbsp; That's what you're
+seeing here.</BLOCKQUOTE>
+
+<HR WIDTH="100%">
+<CENTER>[<A HREF="../../tutorials">Tutorial Index</A>] [<A HREF="page05.html">Continue
+This Tutorial</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/008/page05.html b/docs/tutorials/008/page05.html
new file mode 100644
index 00000000000..4d683a0429e
--- /dev/null
+++ b/docs/tutorials/008/page05.html
@@ -0,0 +1,43 @@
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; I) [Netscape]">
+ <META NAME="Author" CONTENT="James CE Johnson">
+ <TITLE>ACE Tutorial 008</TITLE>
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F">
+
+<CENTER><B><FONT SIZE=+2>ACE Tutorial 008</FONT></B></CENTER>
+
+<CENTER><B><FONT SIZE=+2>Sending and receiving datagrams</FONT></B></CENTER>
+
+
+<P>
+<HR WIDTH="100%">
+<BR>&nbsp;
+<BR>That's it for this tutorial.&nbsp; In the next one we'll add some intelligence
+to the data put into the datagrams.&nbsp; By doing so, we'll be able to
+classify our clients and servers into groups.&nbsp; By combining the data
+content and the server's port we can get fairly fine-grained control over
+who talks to who.
+
+<P>For you convenience:
+<UL>
+<LI>
+<A HREF="server.cpp">server.cpp</A></LI>
+
+<LI>
+<A HREF="directed_client.cpp">directed_client.cpp</A></LI>
+
+<LI>
+<A HREF="broadcast_client.cpp">broadcast_client.cpp</A></LI>
+
+<LI>
+<A HREF="Makefile">Makefile</A></LI>
+</UL>
+
+<HR WIDTH="100%">
+<CENTER>[<A HREF="../../tutorials">Tutorial Index</A>]</CENTER>
+
+</BODY>
+</HTML>
diff --git a/docs/tutorials/008/server.cpp b/docs/tutorials/008/server.cpp
new file mode 100644
index 00000000000..e702b1b93bb
--- /dev/null
+++ b/docs/tutorials/008/server.cpp
@@ -0,0 +1,128 @@
+
+// $Id$
+
+/*
+ Our datagram server will, of course, need to create a datagram.
+ We'll also need an address object so that we know where to listen.
+ */
+#include "ace/SOCK_Dgram.h"
+#include "ace/INET_Addr.h"
+
+/*
+ Use the typical TCP/IP port address for receiving datagrams.
+ */
+static const u_short PORT = ACE_DEFAULT_SERVER_PORT;
+
+int main(int,char**)
+{
+ /*
+ This is where we'll listen for datagrams coming from the
+ clients. We'll give this address to the open() method
+ below to enable the listener.
+ */
+ ACE_INET_Addr local(PORT);
+
+ /*
+ A simply constructed datagram that we'll listen with.
+ */
+ ACE_SOCK_Dgram dgram;
+
+ /*
+ Like most ACE objects, the datagram has to be opened before
+ it can be uses. Of course, -1 on failure.
+
+ A datagram will fail to open if there is already a datagram
+ listening at the port we've chosen. It *is* OK to open
+ a datagram at a port where there is an ACE_SOCK_Stream
+ though. This is because datagrams are UDP and SOCK_Stream
+ is TCP and the two don't cross paths.
+ */
+ if( dgram.open(local) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "open"),-1);
+ }
+
+ /*
+ Create a simple buffer to receive the data. You generally need
+ to provide a buffer big enough for the largest datagram you
+ expect to receive. Some platforms will let you read a little
+ and then some more later but other platforms will throw out
+ whatever part of the datagram you don't get with the first
+ read. (This is on a per-datagram basis BTW.) The theoretical
+ limit on a datagram is about 64k. The realistic limit (because
+ of routers & such) is much smaller. Choose your buffer size
+ based on your application's needs.
+ */
+ char buf[512];
+
+ /*
+ Unlike ACE_SOCK_Stream, datagrams are unconnected. That is,
+ there is no "virtual circuit" between server and client.
+ Because of this, the server has to provide a placeholder
+ for the OS to fill in the source (client) address information
+ on the recv. You can initialize this INET_Addr to anything,
+ it will be overwritten when the data arrives.
+ */
+ ACE_INET_Addr remote;
+
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server daemon\n"));
+
+ /*
+ Receive datagrams as long as we're able.
+ */
+ while( dgram.recv(buf,sizeof(buf),remote) != -1 )
+ {
+ /*
+ Display a brief message about our progress. Notice how we
+ use the 'remote' object to display the address of the client.
+ With an ACE_SOCK_Stream we used get_remote_addr() to get the
+ address the socket is connected to. Because datagrams are
+ unconnected, we use the addr object provided to recv().
+ */
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) Data (%s) from client (%s)\n", buf, remote.get_host_name()));
+
+ /*
+ To respond to the client's query, we have to become a client
+ ourselves. To do so, we need an anonymous local address from
+ which we'll send the response and a datagram in which to send
+ it. (An anonymous address is simply one where we let the OS
+ choose a port for us. We really don't care what it is.O
+ */
+ ACE_INET_Addr local((u_short)0);
+ ACE_SOCK_Dgram client;
+
+ /*
+ Open up our response datagram as always.
+ */
+ if( client.open(local) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "client open"),-1);
+ return(0);
+ }
+
+ /*
+ Build a witty response...
+ */
+ sprintf(buf,"I am here");
+
+ /*
+ and send it to the client. Notice the symetry with the recv()
+ method. Again, the unconnected nature of datagrams forces
+ us to specify an address object with each read/write operation.
+ In the case of read (recv()) that's where the OS stuffs the
+ address of the datagram sender. In the case of write (send())
+ that we're doing here, the address is where we want the network
+ to deliver the data.
+
+ Of course, we're assuming that the client will be listening
+ for our reply...
+ */
+ if( client.send(buf,strlen(buf)+1,remote) == -1 )
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);
+ return(0);
+ }
+ }
+
+ return(0);
+}