diff options
author | jcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1998-09-05 21:05:04 +0000 |
---|---|---|
committer | jcej <jcej@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 1998-09-05 21:05:04 +0000 |
commit | ef1a88ade3bbde1f660baceb470135cd920e0b53 (patch) | |
tree | ee33bff80057b1b4ca600b5ae9a4d8aa61a3787f /docs/tutorials | |
parent | aed7cb18ee0d109023ab548231219adff8e2281a (diff) | |
download | ATCD-ef1a88ade3bbde1f660baceb470135cd920e0b53.tar.gz |
Datagram tutorials begun
Diffstat (limited to 'docs/tutorials')
-rw-r--r-- | docs/tutorials/008/Makefile | 63 | ||||
-rw-r--r-- | docs/tutorials/008/broadcast_client.cpp | 72 | ||||
-rw-r--r-- | docs/tutorials/008/directed_client.cpp | 112 | ||||
-rw-r--r-- | docs/tutorials/008/page01.html | 60 | ||||
-rw-r--r-- | docs/tutorials/008/page02.html | 237 | ||||
-rw-r--r-- | docs/tutorials/008/page03.html | 187 | ||||
-rw-r--r-- | docs/tutorials/008/page04.html | 156 | ||||
-rw-r--r-- | docs/tutorials/008/page05.html | 43 | ||||
-rw-r--r-- | docs/tutorials/008/server.cpp | 128 | ||||
-rw-r--r-- | docs/tutorials/009/Makefile | 63 | ||||
-rw-r--r-- | docs/tutorials/009/broadcast_client.cpp | 44 | ||||
-rw-r--r-- | docs/tutorials/009/directed_client.cpp | 44 | ||||
-rw-r--r-- | docs/tutorials/009/server.cpp | 56 | ||||
-rw-r--r-- | docs/tutorials/index.html | 104 |
14 files changed, 1332 insertions, 37 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 programming, the clients know where the servers +are. A mail client, for instance, has a configuration file that says +where the mail host is. 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? All of the instances are probably +more or less equal to the client's point of view, so you don't want to +"configure" the clients to a single server each. 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. You can toss a datagram out onto +the network and any servers listening at the correct port will* hear it. +Like ACE_SOCK_Stream that we've seen before, you can get the peer address +from a datagram. With that, the server can send a response +back to the client. 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: 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. In the next tutorial, we'll +expand on this to make the server a bit more prudish. +<BR> + +<P><FONT SIZE=-1>* Actually, the servers <I>might</I> hear the datagram. +Datagrams are rather unreliable. (Sort of like some operating systems +I know.) Still, if the network traffic isn't too bad, they generally +get through. 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>. +This is a pretty simple application that listens for datagrams at a known +port and sends back a response. In order to implement a true "discovery" +mechanism, the server will have to be a little bit more picky about who +it responds to. We'll tackle that issue in the next tutorial though... + +<P> +<HR WIDTH="100%"> + +<P><TT>/*</TT> +<BR><TT> Our datagram server will, of course, need to create +a datagram.</TT> +<BR><TT> We'll also need an address object so that we know +where to listen.</TT> +<BR><TT> */</TT> +<BR><TT>#include "ace/SOCK_Dgram.h"</TT> +<BR><TT>#include "ace/INET_Addr.h"</TT> + +<P><TT>/*</TT> +<BR><TT> Use the typical TCP/IP port address for receiving +datagrams.</TT> +<BR><TT> */</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> /*</TT> +<BR><TT> This is where we'll listen +for datagrams coming from the</TT> +<BR><TT> clients. We'll give +this address to the open() method</TT> +<BR><TT> below to enable the listener.</TT> +<BR><TT> */</TT> +<BR><TT> ACE_INET_Addr local(PORT);</TT> + +<P><TT> /*</TT> +<BR><TT> A simply constructed datagram +that we'll listen with.</TT> +<BR><TT> */</TT> +<BR><TT> ACE_SOCK_Dgram dgram;</TT> + +<P><TT> /*</TT> +<BR><TT> Like most ACE objects, the +datagram has to be opened before</TT> +<BR><TT> it can be uses. Of course, +-1 on failure.</TT> + +<P><TT> A datagram will fail to open +if there is already a datagram</TT> +<BR><TT> listening at the port we've +chosen. It *is* OK to open</TT> +<BR><TT> a datagram at a port where +there is an ACE_SOCK_Stream</TT> +<BR><TT> though. This is because +datagrams are UDP and SOCK_Stream</TT> +<BR><TT> is TCP and the two don't cross +paths.</TT> +<BR><TT> */</TT> +<BR><TT> if( dgram.open(local) == -1 )</TT> +<BR><TT> {</TT> +<BR><TT> ACE_ERROR_RETURN ((LM_ERROR, +"%p\n", "open"),-1);</TT> +<BR><TT> }</TT> + +<P><TT> /*</TT> +<BR><TT> Create a simple buffer to +receive the data. You generally need</TT> +<BR><TT> to provide a buffer big enough +for the largest datagram you</TT> +<BR><TT> expect to receive. Some +platforms will let you read a little</TT> +<BR><TT> and then some more later but +other platforms will throw out</TT> +<BR><TT> whatever part of the datagram +you don't get with the first</TT> +<BR><TT> read. (This is on a +per-datagram basis BTW.) The theoretical</TT> +<BR><TT> limit on a datagram is about +64k. The realistic limit (because</TT> +<BR><TT> of routers & such) is +much smaller. Choose your buffer size</TT> +<BR><TT> based on your application's +needs.</TT> +<BR><TT> */</TT> +<BR><TT> char buf[512];</TT> + +<P><TT> /*</TT> +<BR><TT> Unlike ACE_SOCK_Stream, datagrams +are unconnected. That is,</TT> +<BR><TT> there is no "virtual circuit" +between server and client.</TT> +<BR><TT> Because of this, the server +has to provide a placeholder</TT> +<BR><TT> for the OS to fill in the +source (client) address information</TT> +<BR><TT> on the recv. You can +initialize this INET_Addr to anything,</TT> +<BR><TT> it will be overwritten when +the data arrives.</TT> +<BR><TT> */</TT> +<BR><TT> ACE_INET_Addr remote;</TT> + +<P><TT> ACE_DEBUG ((LM_DEBUG, "(%P|%t) starting up server +daemon\n"));</TT> + +<P><TT> /*</TT> +<BR><TT> Receive datagrams as long +as we're able.</TT> +<BR><TT> */</TT> +<BR><TT> while( dgram.recv(buf,sizeof(buf),remote) != +-1 )</TT> +<BR><TT> {</TT> +<BR><TT> /*</TT> +<BR><TT> Display +a brief message about our progress. Notice how we</TT> +<BR><TT> use +the 'remote' object to display the address of the client.</TT> +<BR><TT> With +an ACE_SOCK_Stream we used get_remote_addr() to get the</TT> +<BR><TT> address +the socket is connected to. Because datagrams are</TT> +<BR><TT> unconnected, +we use the addr object provided to recv().</TT> +<BR><TT> */</TT> +<BR><TT> ACE_DEBUG ((LM_DEBUG, +"(%P|%t) Data (%s) from client (%s)\n", buf, remote.get_host_name()));</TT> + +<P><TT> /*</TT> +<BR><TT> To +respond to the client's query, we have to become a client</TT> +<BR><TT> ourselves. +To do so, we need an anonymous local address from</TT> +<BR><TT> which +we'll send the response and a datagram in which to send</TT> +<BR><TT> it. +(An anonymous address is simply one where we let the OS</TT> +<BR><TT> choose +a port for us. We really don't care what it is.O</TT> +<BR><TT> */</TT> +<BR><TT> ACE_INET_Addr +local((u_short)0);</TT> +<BR><TT> ACE_SOCK_Dgram client;</TT> + +<P><TT> /*</TT> +<BR><TT> Open +up our response datagram as always.</TT> +<BR><TT> */</TT> +<BR><TT> if( client.open(local) +== -1 )</TT> +<BR><TT> {</TT> +<BR><TT> +ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "client open"),-1);</TT> +<BR><TT> +return(0);</TT> +<BR><TT> }</TT> + +<P><TT> /*</TT> +<BR><TT> Build +a witty response...</TT> +<BR><TT> */</TT> +<BR><TT> sprintf(buf,"I am here");</TT> + +<P><TT> /*</TT> +<BR><TT> and +send it to the client. Notice the symetry with the recv()</TT> +<BR><TT> method. +Again, the unconnected nature of datagrams forces</TT> +<BR><TT> us +to specify an address object with each read/write operation.</TT> +<BR><TT> In +the case of read (recv()) that's where the OS stuffs the</TT> +<BR><TT> address +of the datagram sender. In the case of write (send())</TT> +<BR><TT> that +we're doing here, the address is where we want the network</TT> +<BR><TT> to +deliver the data.</TT> + +<P><TT> Of +course, we're assuming that the client will be listening</TT> +<BR><TT> for +our reply...</TT> +<BR><TT> */</TT> +<BR><TT> if( client.send(buf,strlen(buf)+1,remote) +== -1 )</TT> +<BR><TT> {</TT> +<BR><TT> +ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT> +<BR><TT> +return(0);</TT> +<BR><TT> }</TT> +<BR><TT> }</TT> + +<P><TT> return(0);</TT> +<BR><TT>}</TT> + +<P> +<HR WIDTH="100%"> + +<P>And that's really all there is to it. Obviously there is some +room for improvement. The most blatant is the somewhat small buffer +size for receiving the datagram. I've never been able to get a solid +answer on datagram sizes. The theoretical limit is just under 64k +but you have to deal with fragmentation. Some readings indicate that +8k is a reasonable size, others go much smaller. My general rule +of thumb is to keep datagrams relatively small (eg -- under 8k or so) and +test a lot. If you find that your routers are fragmenting your larger +datagrams, back off to something smaller. Of course, if you must +send 100k and can only do so 1k at a time, you'll have to worry about retransmissions +& reordering. At that point, you might consider going to TCP. +Remember: datagrams are unreliable! 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. +This is a good thing if you know where the server lives and want to have +a conversation. 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> Once again, we use the default server port. +In a "real" system,</TT> +<BR><TT> the server's port (or ports) would be published in +some way so</TT> +<BR><TT> that clients would know where to "look". We +could even add entries</TT> +<BR><TT> to the operating system's services file and use a +service name</TT> +<BR><TT> instead of a number. We'll come back to that +in some other tutorial</TT> +<BR><TT> though. For now, let's stay simple.</TT> +<BR><TT> */</TT> +<BR><TT>static const u_short PORT = ACE_DEFAULT_SERVER_PORT;</TT> + +<P><TT>/*</TT> +<BR><TT> Our goal here is to develop a client that can send +a datagram to</TT> +<BR><TT> a server running on a known host. We'll use +a command-line argument</TT> +<BR><TT> to specify the hostname instead of hard-coding it.</TT> +<BR><TT> */</TT> +<BR><TT>int main(int argc,char *argv[] )</TT> +<BR><TT>{</TT> +<BR><TT> /*</TT> +<BR><TT> All +datagrams have to have a point of origin. Since we intend to</TT> +<BR><TT> transmit +instead of receive, we initialize an address with zero</TT> +<BR><TT> and +let the OS choose a port for us. We could have chosen our</TT> +<BR><TT> own +value between 1025 and 65535 as long as it isn't already in use.</TT> +<BR><TT> */</TT> +<BR><TT> ACE_INET_Addr +local((u_short)0);</TT> + +<P><TT> /*</TT> +<BR><TT> And +here is our datagram object.</TT> +<BR><TT> */</TT> +<BR><TT> ACE_SOCK_Dgram dgram;</TT> +<BR><TT> </TT> +<BR><TT> /*</TT> +<BR><TT> Notice +that this looks a lot like the server application. There's</TT> +<BR><TT> no +difference in creating server datagrams an client datagrams.</TT> +<BR><TT> You +can even use a zero-constructed address for your server datagram</TT> +<BR><TT> as +long as you tell the client where you're listening (eg -- by writting</TT> +<BR><TT> into +a file or some such).</TT> +<BR><TT> */</TT> +<BR><TT> if( dgram.open(local) +== -1 )</TT> +<BR><TT> {</TT> +<BR><TT> +ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1);</TT> +<BR><TT> }</TT> + +<P><TT> /*</TT> +<BR><TT> Yep. +We've seen this before too...</TT> +<BR><TT> */</TT> +<BR><TT> char buf[512];</TT> + +<P><TT> /*</TT> +<BR><TT> Ok, +now we're doing something different.</TT> +<BR><TT> */</TT> +<BR><TT> sprintf(buf, "Hello +World!");</TT> + +<P><TT> /*</TT> +<BR><TT> Just +like sending a telegram, we have to address our datagram.</TT> +<BR><TT> Here, +we create an address object at the desired port on the</TT> +<BR><TT> chosen +host. To keep us from crashing, we'll provide a default</TT> +<BR><TT> host +name if we aren't given one.</TT> +<BR><TT> */</TT> +<BR><TT> ACE_INET_Addr +remote(PORT, argc > 1 ? argv[1] : "localhost" );</TT> + +<P><TT> ACE_DEBUG ((LM_DEBUG, +"(%P|%t) Sending (%s) to the server.\n",buf));</TT> +<BR><TT> /*</TT> +<BR><TT> +Now we send our buffer of stuff to the remote address. This is</TT> +<BR><TT> +just exactly what the server did after receiving a client message.</TT> +<BR><TT> +Datagrams are rather orthogonal that way: they don't generally make</TT> +<BR><TT> +much of a fuss about being either client or server.</TT> +<BR><TT> */</TT> +<BR><TT> if( dgram.send(buf,strlen(buf)+1,remote) +== -1 )</TT> +<BR><TT> {</TT> +<BR><TT> +ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT> +<BR><TT> }</TT> + +<P><TT> /*</TT> +<BR><TT> Now +we've turned around and put ourselves into "server mode" by</TT> +<BR><TT> invoking +the recv() method. We now our server is going to send</TT> +<BR><TT> us +something, so we hang out here and wait for it. Because we</TT> +<BR><TT> know +datagrams are unreliable, there is a chance that the server</TT> +<BR><TT> will +respond but we won't hear. You might consider providing a</TT> +<BR><TT> timeout +on the recv() in that case. If recv() fails due to timeout</TT> +<BR><TT> it +will return -1 and you can then resend your query and attempt</TT> +<BR><TT> the +recv() again.</TT> +<BR><TT> */</TT> +<BR><TT> if( dgram.recv(buf,sizeof(buf),remote) +== -1 )</TT> +<BR><TT> {</TT> +<BR><TT> +ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1);</TT> +<BR><TT> }</TT> + +<P><TT> /*</TT> +<BR><TT> Find +out what the server had to say.</TT> +<BR><TT> */</TT> +<BR><TT> ACE_DEBUG ((LM_DEBUG, +"(%P|%t) The server said: %s\n",buf));</TT> + +<P><TT> 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. 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. +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> +<BR> 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. +I have to say <I>(sub)network</I> because broadcast datagrams typically +are not passed through routers. 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> ACE_INET_Addr +local((u_short)0);</TT> + +<P><TT> /*</TT> +<BR><TT> Instead +of creating the ACE_SOCK_Dgram we created last time,</TT> +<BR><TT> we'll +create an ACE_SOCK_Dgram_Bcast. "Bcast" means, of course,</TT> +<BR><TT> "Broadcast". +This ACE object is clever enough to go out to the</TT> +<BR><TT> OS +and find all of the network interfaces. When you send()</TT> +<BR><TT> on +a Dgram_Bcast, it will send the datagram out on all of those</TT> +<BR><TT> interfaces. +This is quiet handy if you do it on a multi-homed</TT> +<BR><TT> host +that plays router...</TT> +<BR><TT> */</TT> +<BR><TT> ACE_SOCK_Dgram_Bcast +dgram;</TT> + +<P><TT> if( dgram.open(local) +== -1 )</TT> +<BR><TT> {</TT> +<BR><TT> +ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "datagram open"),-1);</TT> +<BR><TT> }</TT> + +<P><TT> char buf[512];</TT> + +<P><TT> sprintf(buf, "Hello World!");</TT> + +<P><TT> /*</TT> +<BR><TT> The +only other difference between us and the directed client</TT> +<BR><TT> is +that we don't specify a host to receive the datagram.</TT> +<BR><TT> Instead, +we use the magic value "INADDR_BROADCAST". All hosts</TT> +<BR><TT> are +obliged to respond to datagrams directed to this address</TT> +<BR><TT> the +same as they would to datagrams sent to their hostname.</TT> + +<P><TT> Remember, +the Dgram_Bcast will send a datagram to all interfaces</TT> +<BR><TT> on +the host. That's true even if the address is for a specific</TT> +<BR><TT> host +(and the host address makes sense for the interface).</TT> +<BR><TT> The +real power is in using an INADDR_BROADCAST addressed datagram</TT> +<BR><TT> against +all interfaces.</TT> +<BR><TT> */</TT> +<BR><TT> ACE_INET_Addr +remote(PORT,INADDR_BROADCAST);</TT> + +<P><TT> ACE_DEBUG ((LM_DEBUG, +"(%P|%t) Sending (%s) to the server.\n",buf));</TT> +<BR><TT> </TT> +<BR><TT> if( dgram.send(buf,strlen(buf)+1,remote) +== -1 )</TT> +<BR><TT> {</TT> +<BR><TT> +ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "send"),-1);</TT> +<BR><TT> }</TT> + +<P><TT> if( dgram.recv(buf,sizeof(buf),remote) +== -1 )</TT> +<BR><TT> {</TT> +<BR><TT> +ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "recv"),-1);</TT> +<BR><TT> }</TT> + +<P><TT> ACE_DEBUG ((LM_DEBUG, +"(%P|%t) The server said: %s\n",buf));</TT> + +<P><TT> /*</TT> +<BR><TT> Using +the <I>remote</I> object instance, find out where the server lives.</TT> +<BR><TT> We +could then save this address and use directed datagrams to chat</TT> +<BR><TT> with +the server for a while.</TT> +<BR><TT> */</TT> +<BR><TT> ACE_DEBUG ((LM_DEBUG, +"(%P|%t) The server can be found at: (%s:%d)\n",</TT> +<BR><TT> +remote.get_host_addr(), PORT ));</TT> +<BR><TT> </TT> +<BR><TT> return(0);</TT> +<BR><TT>}</TT> + +<P> +<HR WIDTH="100%"> + +<P> 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. +What do you do, though, if you need to get past a router? My advice +is to write a server that will run on hosts on both sides of your router. +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. +The counterpart would then re-broadcast the original datagram on that sub-net. +Cheap, simple and effective.</BLOCKQUOTE> +One final word of warning: +<BLOCKQUOTE>When creating your broadcast datagrams you may see something +like this: <I>ACE_SOCK_Dgram_Bcast::mk_broadcast: Broadcast is not +enable for this interface.: Unknown error</I>. There are some interfaces +(ppp, slip) that don't support broadcast datagrams. 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> +<BR>That's it for this tutorial. In the next one we'll add some intelligence +to the data put into the datagrams. By doing so, we'll be able to +classify our clients and servers into groups. 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); +} diff --git a/docs/tutorials/009/Makefile b/docs/tutorials/009/Makefile new file mode 100644 index 00000000000..59ac6bca63f --- /dev/null +++ b/docs/tutorials/009/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/009/broadcast_client.cpp b/docs/tutorials/009/broadcast_client.cpp new file mode 100644 index 00000000000..a8ec3cbb596 --- /dev/null +++ b/docs/tutorials/009/broadcast_client.cpp @@ -0,0 +1,44 @@ + +// $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); + ACE_INET_Addr remote(PORT,INADDR_BROADCAST); + ACE_SOCK_Dgram_Bcast dgram; + + if( dgram.open(local) == -1 ) + { + cerr << "Cannot create client datagram" << endl; + return(0); + } + + char buf[512]; + + sprintf(buf, argc > 1 ? argv[1] : "Hello World!"); + + if( dgram.send(buf,strlen(buf)+1,remote) == -1 ) + { + cerr << "Failed to send datagram" << endl; + return(0); + } + + if( argc > 1 ) + { + ACE_Time_Value timeout(2,0); + if( dgram.recv(buf,sizeof(buf),remote,0,&timeout) == -1 ) + { + cerr << "Failed to receive server's response" << endl; + return(0); + } + + cerr << "Server responded with: " << buf << endl; + } + + return(0); +} diff --git a/docs/tutorials/009/directed_client.cpp b/docs/tutorials/009/directed_client.cpp new file mode 100644 index 00000000000..7214ba653fa --- /dev/null +++ b/docs/tutorials/009/directed_client.cpp @@ -0,0 +1,44 @@ + +// $Id$ + +#include "ace/SOCK_Dgram.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); + ACE_INET_Addr remote(PORT, argc > 1 ? argv[1] : "localhost" ); + ACE_SOCK_Dgram dgram; + + if( dgram.open(local) == -1 ) + { + cerr << "Cannot create client datagram" << endl; + return(0); + } + + char buf[512]; + + sprintf(buf, argc > 2 ? argv[2] : "Hello World!"); + + if( dgram.send(buf,strlen(buf)+1,remote) == -1 ) + { + cerr << "Failed to send datagram" << endl; + return(0); + } + + if( argc > 2 ) + { + ACE_Time_Value timeout(2,0); + if( dgram.recv(buf,sizeof(buf),remote,0,&timeout) == -1 ) + { + cerr << "Failed to receive server's response" << endl; + return(0); + } + + cerr << "Server responded with: " << buf << endl; + } + + return(0); +} diff --git a/docs/tutorials/009/server.cpp b/docs/tutorials/009/server.cpp new file mode 100644 index 00000000000..5c6087a15c8 --- /dev/null +++ b/docs/tutorials/009/server.cpp @@ -0,0 +1,56 @@ + +// $Id$ + +#include "ace/SOCK_Dgram.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(PORT); + ACE_SOCK_Dgram dgram; + + if( dgram.open(local) == -1 ) + { + cerr << "Listener failed to open" << endl; + return(0); + } + + char buf[512]; + ACE_INET_Addr remote; + + while( dgram.recv(buf,sizeof(buf),remote) != -1 ) + { + cerr << "Received: " << buf << " from " << remote.get_host_name() << endl; + + if( argc > 1 ) + { + /* Respond to the client's query + */ + if( ACE_OS::strcmp(buf,argv[1]) ) + { + cerr << "Client query does not match our signature" << endl; + } + else + { + ACE_INET_Addr local((u_short)0); + ACE_SOCK_Dgram client; + if( client.open(local) == -1 ) + { + cerr << "Cannot open response dgram" << endl; + return(0); + } + + sprintf(buf,"I am here"); + if( client.send(buf,strlen(buf)+1,remote) == -1 ) + { + cerr << "Failed to send response to client" << endl; + return(0); + } + } + } + } + + return(0); +} diff --git a/docs/tutorials/index.html b/docs/tutorials/index.html index d9446a12e08..7c63f7d1e88 100644 --- a/docs/tutorials/index.html +++ b/docs/tutorials/index.html @@ -8,15 +8,15 @@ <BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#000FFF" VLINK="#FF0F0F"> <HR> -<H3>ACE Tutorial Introduction</H3><P> - -The original audience for these tutorials was the <A -HREF="http://www.lads.com">Automated Design Systems</A> (ADS) IPC -team, lead by <A HREF="mailto:jcej@lads.com">James Johnson</A>. Since -then, the scope has been changed to include anyone who wants to learn -about the ACE framework. Hopefully, even experienced ACE programmers -will find something new here. With a framework as encompassing as ACE, -it is easy to become an expert in one area and know little or nothing +<H3> +ACE Tutorials</H3> + +<HR WIDTH="100%">The original audience for these tutorials was the <A HREF="http://www.lads.com">Automated +Design Systems</A> (ADS) IPC team, lead by <A HREF="mailto:jcej@lads.com">James +Johnson</A>. Since then, the scope has been changed to include anyone who +wants to learn about the ACE framework. Hopefully, even experienced ACE +programmers will find something new here. With a framework as encompassing +as ACE, it is easy to become an expert in one area and know little or nothing about others. <P> @@ -42,66 +42,96 @@ available UNIX implementations like <A HREF="http://www.labs.redhat.com/">Linux< real-time operating systems (e.g., <A HREF="http://www.lynx.com/">LynxOS</A>, <A HREF="http://www.wrs.com">VxWorks</A>, and <A HREF="http://www.isi.com/">PSoS</A>), and <A HREF="http://www.s390.ibm.com/products/oe/index.html">MVS OpenEdition</A>. -A single <A HREF="ACE-directory.html">source tree</A> is used for all these -platforms. There is also a <A HREF="http://www.cs.wustl.edu/~eea1/JACE.html">Java</A> -version of ACE.<P> - -<HR width=50% align=left><P> -<H3>Why Use ACE?</H3> +A single <A HREF="http://localhost/~jcej/ACE/ACE_wrappers/etc/tutorials/ACE-directory.html">source +tree</A> is used for all these platforms. There is also a <A HREF="http://www.cs.wustl.edu/~eea1/JACE.html">Java</A> +version of ACE. +<H3> +Why Use ACE?</H3> A key reason to use ACE is simple: <I>write a multi-threaded networked application on one platform and quickly be able to use it on another</I>. This is important for many projects because it is necessary for applications to communicate with one another. For instance, many applications will exist -on both UNIX and Win32 platforms within a local area network. <P> - -<HR width=50% align=left><P> -<H3>What about TAO?</H3> +on both UNIX and Win32 platforms within a local area network. +<H3> +What about TAO?</H3> In the early stages, these tutorials won't address The ACE ORB (<A HREF="http://www.cs.wustl.edu/~schmidt">TAO</A>). However, if you want to request a tutorial on some aspect of TAO or even create one yourself, I'll be glad to integrate those into these tutorials. It's rare when folks want to write documentation, so nothing will be refused! + <P> <HR WIDTH="100%"> -<H3>The Tutorials</H3><P> - -The following tutorials have been designed to guide you through the -process of learning ACE. We will continue to add new tutorials over -time. <P> +<H3> +The Tutorials</H3> -<HR width=50% align=left><P> -<H4>Basic Client/Server Tutorials</H4> +<UL> +<H4> +Your basic Client/Server hookup</H4> +</UL> <OL> +<OL> <LI> -<A HREF="001/page01.html">A Simple Server</A></LI> +<A HREF="http://localhost/~jcej/ACE/ACE_wrappers/etc/tutorials/001/page01.html">A +Simple Server</A></LI> <LI> -<A HREF="002/page01.html">A Simpler Server</A></LI> +<A HREF="http://localhost/~jcej/ACE/ACE_wrappers/etc/tutorials/002/page01.html">A +Simpler Server</A></LI> <LI> -<A HREF="003/page01.html">Finally, a Client</A></LI> +<A HREF="http://localhost/~jcej/ACE/ACE_wrappers/etc/tutorials/003/page01.html">Finally, +a Client</A></LI> <LI> -<A HREF="004/page01.html">A much <I>cooler</I> client</A></LI> -</OL><P> +<A HREF="http://localhost/~jcej/ACE/ACE_wrappers/etc/tutorials/004/page01.html">A +much <I>cooler</I> client</A></LI> +</OL> -<HR width=50% align=left><P> -<H4>Concurrency Tutorials</H4> +<H4> +A word about concurrency</H4> <OL> <LI> -<A HREF="005/page01.html">No threads, nothing fancy, just do the work!</A></LI> +<A HREF="http://localhost/~jcej/ACE/ACE_wrappers/etc/tutorials/005/page01.html">No +threads, nothing fancy, just do the work!</A></LI> <LI> -<A HREF="006/page01.html">I'd like to dedicate... a thread to each connection.</A></LI> +<A HREF="http://localhost/~jcej/ACE/ACE_wrappers/etc/tutorials/006/page01.html">I'd +like to dedicate... a thread to each connection.</A></LI> <LI> -<A HREF="007/page01.html">Let's pool our resources: a fixed-size pool of threads.</A></LI> +<A HREF="http://localhost/~jcej/ACE/ACE_wrappers/etc/tutorials/007/page01.html">Let's +pool our resources: a fixed-size pool of threads.</A></LI> </OL> +<H4> +Finding servers on your network</H4> + +<OL> +<LI> +<A HREF="008/page01.html">Calling +all servers!</A></LI> +<!-- +<LI> +<A HREF="009/page01.html">Discriminating tastes...</A></LI> +</OL> + +<H4> +A word about ACE_Message_Queue</H4> + +<OL> +<LI> +React to this!</LI> + +<LI> +putq, putq, putq...</LI> +--> +</OL> +</OL> <HR> -<P>Back to the <A HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/docs/ACE-tutorials.html">ACE +<P>Back to the <A HREF="http://www.cs.wustl.edu/~schmidt/ACE_wrappers/etc/ACE-tutorials.html">ACE tutorials</A> page. <P><!--<EM> |