/** @page tutorial_simple A simple client/server Let's take a look at a really simple Atlas-C++ client and server. All that the server was is wait for a connection, receive something from the client and wait for the connection to close. The client connects to the server, sends a message and then closes the connection. Both client and server use libsocket++ (see @ref tutorial_preamble) for socket communications. @section general General Concepts @subsection atlas About Atlas I assume you already know a little about the way Atlas works. Broadly speaking it allows the transmission of messages, which can contain objects of different types. These types are integers, floating-point values, character strings, lists of objects and lastly maps (which are keyed lists, such as perl hashes, python dicts, and STL maps). Atlas-C++ allows you to comfortably send and receive such messages in a stream fashion through iostreams (which can be socket streams), without ever having to deal with the Atlas protocol itself. @subsection codecs Codecs The Atlas "protocol" is an implementation-independent definition. This means you can express atlas messages in different ways, such as in an XML-like fashion, in a simple ASCII protocol or in a very space-efficient binary protocol. Such protocol implementations are called "codecs". An Atlas-C++ Codec takes an iostream as parameter at construction and has functions for sending the various different types of values (maps, lists and single values). Each codec also provides a function called Poll(). This gets a character from the stream (note that it will block - so check your socket first!) and parses it. "That's great," I hear you say, "but how do I get the data that it receives?" Well, this is where one of the neat things about Atlas-C++ comes in: Bridges. @subsection bridges Bridges Codec is in fact publicly derived from Bridge. Bridge is an abstract class which contains all those functions to send maps, lists and other values. The neat thing about Bridge is though that it is symmetric. That means it's not just used to send messages, but also to receive them. So, when you create a Codec you pass it a pointer to a Bridge as well. The virtual functions in that Bridge get called whenever parts of a message are received. So, you can put whatever you want to do with that data into a Bridge of your own, pass an instance of that to the Codec, and you will have instant satisfaction! :) @subsection negotiation Negotiation Now, it would be a hassle if you would have to check which codecs the peer you are connecting to has each time you make a new connection, since Atlas-C++ supports any number of different codecs. But fear not, for Atlas-C++ does even this for you. Whenever you connect to a server or client, you first enter a negotiation stage, in which the client and server decide which Codec to use. This is done by creating a Net::StreamAccept object in the server or a Net::StreamConnect object in the client, passing the name of the server/client, the Bridge to be used by the Codec and the stream on which the connection has been established. You then repeatedly call the Poll() method of these classes until their state is not IN_PROGRESS any more. If negotiation was successful, you can retrieve the codec to be used with GetCodec(), and then go on sending and receiving messages happily with your peer. If negotation failed, GetState() will return FAILURE, and you may abort the connection and alert the user. @subsection filters Filters Lastly, it should be noted that not only codecs exist, but also filters. These "wrap around" the codecs and do things like bzip2/gzip compression, or encryption. These are represented in Atlas-C++ by the Filter class, and also automatically negotiated by the Negotiation classes. This means that while coding you never actually have to worry about them. @subsection magic Automagic detection You should know that Atlas-C++ will automagically detect what codecs and filters are linked into your application, so you will never need to provide lists of these or any such inconveniences. @section server The Server See under the code for more documentation. Note: If the server does not seem to be accepting connections, try changing bind("0.0.0.0", 6767) to bind("127.0.0.1", 6767) (or other similar addresses that might be appropriate. @verbinclude simple_server.cc As mentioned before, the server does the following:
  1. Wait for a connection
  2. Accept a client connection
  3. Negotiate with the connecting client
  4. Receive messages from the client and wait for it to disconnect
Only steps 3 and 4 really involve Atlas-C++, the rest is handled by the socket library I'm using (libsocket++, see @ref tutorial_preamble). @section client The Client @verbinclude simple_client.cc The client corresponds with the server by doing the following:
  1. Connect to the server
  2. Negotiate a server connection
  3. Send a message
  4. Sleep a little while
  5. Close the connection
Again, only steps 2, 3 and 5 involve dealing with Atlas-C++. The code should be pretty straightforward to understand if you have read the @ref general. @section debug_bridge DebugBridge In the above client + server a class called DebugBridge is used. This class is not part of Atlas-C++, but rather one that we made ourselves. It is passed to the negotiation classes (StreamConnect and StreamAccept) which then pass it on to the codec returned by GetCodec(). DebugBridge simply prints out everything it receives onto cout. The source code should be quite easily understandable. @verbinclude DebugBridge.h @ref tutorial_preamble "Previous" @ref tutorial_index "Index" @ref tutorial_message "Next" @author Stefanus Du Toit */