wesnoth/doc/ana/description.tex

557 lines
19 KiB
TeX

\documentclass[a4paper,12pt,english]{article}
\newcommand{\ana}{\textbf{ana}}
\usepackage{listings}
% \usepackage{setspace}
\usepackage{color}
\usepackage{textcomp}
\definecolor{listinggray}{gray}{0.9}
\definecolor{lbcolor}{rgb}{0.95,0.95,0.95}
\lstset{
backgroundcolor=\color{lbcolor},
tabsize=4,
rulecolor=,
language=matlab,
basicstyle=\scriptsize,
upquote=true,
aboveskip={1.5\baselineskip},
columns=fixed,
showstringspaces=false,
extendedchars=true,
breaklines=true,
prebreak = \raisebox{0ex}[0ex][0ex]{\ensuremath{\hookleftarrow}},
frame=single,
showtabs=false,
showspaces=false,
showstringspaces=false,
identifierstyle=\ttfamily,
keywordstyle=\color[rgb]{0.1,0.1,0.6}\bfseries,
commentstyle=\color[rgb]{0.133,0.545,0.133},
stringstyle=\color[rgb]{0.627,0.126,0.941},
}
\title{Developing Server/Client applications \\
using the \ana \ API/library}
\author{Guillermo Biset}
\begin{document}
\maketitle
\vfill
\begin{abstract}
Developing network applications is no easy task. Most of the time, the
important features are not even network-related, yet the implementers
spend most of their time coding to get this part of the functionality
right.
This document introduces \ana, an API designed to let you develop
simple network server and client applications using an asynchronous
(i.e. non blocking) model in C++ without having to deal directly with
network components such as sockets.
\end{abstract}
\newpage
\tableofcontents
\newpage
\section{Preliminaries}
\textbf{Disclaimer}: This section contains no technical information
whatsoever.
\section{Introduction}
\textbf{Ana} (stands for Asynchronous Network API) is an API designed
to help you develop network applications with server and client parts.
To implement this functionality, the API uses an asynchronous model
(i.e. non-blocking operations .) This way, the progammer doesn't need
to pay too much attention to the network code itself but can
concentrate on other features relevant to the program.
Also, \ana \ comes with an accompanying implementation. Hence, it is
also a library that implements the API features. For example, MPI is
an API for message passing and LAM/MPI is a library that implements
it. Further on it is possible that the two will be separated, but this
is unlikely at the moment.
The dynamics involved in writing server/client applications using \ana
\ is fairly simple. There are interfaces designed for each set of
handlers relevant to network events (described in later sections) that
one must implement and every event will be issued by a corresponding
component with a unique ID.
In the simpler cases, developing a server involves:
\begin{enumerate}
\item Creating an \ana::server object.
\item Running it on a given port.
\item Having a class of your own inherit from the corresponding
interfaces to handle network events.
\item Implement these handlers.
\end{enumerate}
The client side implementation is analogous:
\begin{enumerate}
\item Create an \ana::client object.
\item Instruct it to connect to a given address:port.
\item Create classes that inherit from the corresponding
interfaces to handle network events.
\item Implement these handlers.
\end{enumerate}
\section{On Asynchronous Operations}
Evidently, implementing these handlers may not be so simple. However,
a large amount of functionality may be achieved from simple
implementations in them.
Every operation in \ana \ is asynchronous, which is both a good
feature and a bad one. The drawback is that some assumptions usually
made about function invocation require thinking twice about them.
The main problem is not understanding fully what the function does, in
our case, and as an example, a \texttt{send} operation does not
necessarily return after it has sent any data to anyone, it just
\emph{queues} the corresponding operation, thus leaving the work to be
carried out at a later time.
It is through the invocation of the handler that one can understand
what happened.
For example:
\begin{itemize}
\item Returning from a send operation doesn't mean the data was
sent (you just started sending it, the library will let you know
when the operation was completed.)
\item Returning from a connect operation doesn't mean the client
succesfully connected to the server (you just instructed it to
start a connection attempt.)
\item Implementing the handler for an event involves error
checking to see if the event failed and, if you performed
several operations of a single type (e.g. many send operations)
you won't be able to identify which of these failed (since the
error belongs only to \textit{one} of these.)
\end{itemize}
%\section{Features}
%\textbf{Ana} incorporates the following features:
%\begin{description}
% \item [
%\end{description}
\section{API overview}
\subsection{Namespaces}
The list of namespaces is as follows:
\begin{description}
\item[\ana] : Main namespace.
\item[\ana::time] : Functions to build time durations
(i.e. \ana::time::seconds.)
\item[\ana::detail] : Implementation specific definitions.
\end{description}
The whole API can be found under one namespace: \ana. From now on I
will refer to elements in the \ana \ namespace using C++ scope
operator ::, for instance, method \texttt{f} from namespace \ana \ may
be referred to as \ana::\texttt{f}.
Since timeout configuration (to be discussed) may be done using
different functions to construct time durations, a \textbf{time}
namespace is added to \ana. So, the \ana::\textbf{time} namespace
contains functions for creating time durations.
The last namespace, and the one least relevant to the user of the API
is the namespace \textbf{detail}, enclosing all implementation related
code.
\subsection{Basic Types Defined}
Here is a list of some of the simple types defined under the \ana
\ namespace
\begin{description}
\item [ana\_uint] : Standard unsigned int. This type should be used
if you expect to serialize data in an object, send it over the
network, and then extract it on the other side (which may have a
different architecture.)
\item [ana\_int] : Standard int. Idem.
\item [client\_id] : A unique ID of a network component. This type
has a total order, so it can be compared to other instances of
its type. A server will have an ID equal to zero and every client
a greater than zero value.
\item [port] : A string representing a port descriptor, the string
should be able to cast itself to a unsigned short int.
\item [address] : A string representing a network address, it may
be an IP address of a hostname.
\item [send\_type] : Send operation type, this is related to the
lifecycle of the buffer used in the send operation, which may
involve copying the buffer or not (this can result in great
improvement regarding memory usage.) A value of this type may be
evaluated as a boolean (where \emph{true} means to copy the
buffer.) To set a value, constants \texttt{ZeroCopy} and
\texttt{CopyBuffer} are provided. See section \ref{bufcopy} for
more information.
\item [error\_code] : Descriptor of an error code. It can also
evaluate to a boolean value where \emph{false} means no error
occurred.
\end{description}
\subsection{Main Classes}
The main classes to be used from the \ana \ API are:
\begin{description}
\item[ana::server] : A network server. An object of this type can
handle several connected clients. It is possible to create pointers
to an object of this type using the function
\ana::\texttt{create\_server}.
\item[ana::client] : A network client. A network entity that can
connect to a running server. To create a pointer to an object of
this type use the \ana::\texttt{create\_client} function.
\item[ana::timer] : An asynchronous deadline timer that can be used
for general purposes.
\end{description}
\subsection{Main Interfaces}
\begin{description}
\item[\ana::listener\_handler] : Should be implemented to handle
incoming messages and the disconnection of a connected component.
\item[\ana::connection\_handler] : Handling of new connections.
\item[\ana::send\_handler] : Handling completed or failed send events.
\end{description}
\subsection{Extras}
\subsubsection{Timers}
Besides supporting configurable timeouts on send operations, \ana
\ provides a simple timer interface to be used for general purposes.
One can create timers and set them to call a specific handler after a
certain amount of time has passed.
To create these time lapses functions are provided under the
\textbf{time} namespace for milliseconds, seconds, minutes and hours,
and these functions may be used in both cases (instructing a general
purpose timer to wait for given amount of time or configuring the
amount of time required for a timeout event on a send operation.)
Here are a few examples of how to construct time durations:
\begin{center}
\begin{tabular}{|l|l|}
\hline
Five minutes & \texttt{ana::time::minutes(5)} \\
\hline
A second and a half & \texttt{ana::time::seconds(1.5)} \\
\hline
One hour and ten milliseconds & \texttt{ana::time::hours(1)} + \\
\ & \texttt{ana::time::milliseconds(10)} \\
\hline
\end{tabular}
\end{center}
There are two ways of creating timers, via an \ana \ component or
using the type directly. You should always try to use ana's server and
client objects to create them via the function
\ana::\texttt{create\_timer}.
The easy way is using the type directly to declare regular variables.
However, this burdens the memory greatly in comparison of using an
\ana \ component (either server or client) to create the timer for
you.
\section{Using the API}
\subsection{Important Recommendations}
Here are some very important recommendations about using
\ana. Explanations can be found in the following subsection.
\begin{itemize}
\item If you are unsure about the consistency of the memory region
you are using to send data, then use a send operation that copies
the buffer before using it (this ensures that the buffer is
copied before the invocation to the operation returns.)
There are two ways to accomplish this, but to keep things short,
just use the default send operation without setting that specific
parameter (e.g. \texttt{server\_->send\_all( ana::buffer ( str )
) } .)
\item Always prefer single multiple-send operations (e.g.
\texttt{send\_if}) to executing many times a single-send
operation (\texttt{send\_one}.)
\item If you are \textbf{absolutely} sure the memory you'll be
using for the send buffer will be consistent from the time of the
invocation to the send operation to the invocation of its
associated handler, then use a zero copy send operation
(e.g. \texttt{server\_->send\_all( ana::buffer( str ),
ana::ZeroCopy ) } .)
\item Use the code as if handlers are called in a mutually
exclusive way, but they are executed concurrently with the rest
of your application code.
\end{itemize}
\subsection{Details about Buffers}
\label{bufcopy}
There is a reason why multiple-send operations are better. If you are
using a multiple-send operation ( \texttt{send\_all},
\texttt{send\_if} ) that copies the buffer (the default behavior) then
the buffer will be copied only once. Also, sending to each client will
read from that original buffer. Finally, the buffer will be destructed
automatically after the last handler has been called.
\subsection{Details about Threads}
\textbf{Ana} can't intercede between you and the rest of your program,
this means that it can't ensure mutual exclusion between its code and
your own. What it can ensure is that the handlers you implemented will
be called from a single thread (i.e. there won't be two different
handlers running concurrently.)
But this forces the user of the API to take this case under
consideration and implement its own mutual exclusion
mechanism. However, the most common scenario will have a clear
separation between the rest of the program and the code using \ana.
For instance, there is no shared data structure between \ana \ and its
user. The case to look out for is when the implementation of the
network event handlers happen to modify data that is also modified
within the rest of the code.
\section{Example: Chat Application}
This section describes the devolopment of a chat server and client
applications. There is nothing interesting about it except the fact
that it serves to show how one would go about using \ana.
First of all, we will develop two separate executable files, one for
the server and one for the client. The server application will start a
chat server in a given port and connect clients, keeping track of their
assigned names. It also provides commands to change a client's name and
listing everyone connected.
A client can connect to a running server and send messages or commands
to it. Regular messages will in turn be broadcasted to every other
client (prepending the name of the originating client first) and commands
executed.
Since the client application is simpler, lets look at code for it first.
\subsection{Client Code}
The main function is very straightforward, it just creates a \texttt{ChatClient}
object and tells it to run according to parameters taken from the command
line. So, if the executable is \texttt{client} one may execute the
following command: \texttt{./client -n billy -a address.com -p 12345}.
\begin{table}[!htb]
\lstset{language=C++}
\begin{lstlisting}[frame=single]
int main(int argc, char **argv)
{
GetOpt_pp options(argc, argv);
if (options >> OptionPresent('h', "help"))
show_help();
else
{
port pt(DEFAULT_PORT);
std::string address(DEFAULT_ADDRESS);
std::string name("Unnamed");
options >> Option('p', "port", pt)
>> Option('a',"address",address)
>> Option('n',"name",name);
std::cout << "Main client app.: Starting client" << std::endl;
ChatClient client(address,pt,name);
client.run();
}
}
\end{lstlisting}
\centering \caption{The client's main function.}
\label{client-main}
\end{table}
So, not much to look at here, move along. Table \ref{chatclient-decl} is a little
more interesting and shows how one should declare classes to implement the
handler methods relevant to network events.
\begin{table}[!htb]
\lstset{language=C++}
\begin{lstlisting}[frame=single]
class ChatClient : public ana::listener_handler,
public ana::send_handler,
public ana::connection_handler
{
public:
ChatClient(const std::string& address, port pt, std::string name)
: continue_(true),
client_( create_client(address,pt) ),
name_(name)
{
}
void run();
/* ... */
private:
/* Handler profiles. */
virtual void handle_connect( ana::error_code error,
ana::client_id server_id );
virtual void handle_disconnect( ana::error_code error,
ana::client_id server_id);
virtual void handle_receive( ana::error_code error,
ana::client_id,
ana::detail::read_buffer msg);
virtual void handle_send( ana::error_code error,
ana::client_id client);
/* Attributes. */
bool continue_;
ana::client* client_;
std::string name_;
};
\end{lstlisting}
\centering \caption{A class that will implement handlers (all of them in this case.)}
\label{chatclient-decl}
\end{table}
\begin{table}[!htb]
\lstset{language=C++}
\begin{lstlisting}[frame=single]
void ChatClient::run()
{
try
{
client_->connect( this );
client_->set_listener_handler( this );
client_->run();
// list available commands
run_input(); // read lines and send them
}
catch(const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
delete client_;
}
\end{lstlisting}
\centering \caption{Running a client application.}
\label{client-run}
\end{table}
For this particular client application most handlers are trivial, method
\texttt{handle\_disconnect} simply informs that the server disconnected
and sets things up to quit, function \texttt{handle\_message} prints the
incoming message and \texttt{handle\_send} reports the error if it occurred.
Method \texttt{handle\_connect} has some interest to it since it tells the
server what its desired name is. Table \ref{client-connect} shows the
corresponding code.
\begin{table}[!htb]
\lstset{language=C++}
\begin{lstlisting}[frame=single]
virtual void handle_connect( ana::error_code error, client_id server_id )
{
if ( error )
std::cerr << "Error connecting." << std::endl;
else
client_->send( ana::buffer( std::string("/name ") + name_) , this);
}
\end{lstlisting}
\centering \caption{Implementation of the connection handler in the chat client's app.}
\label{client-connect}
\end{table}
\subsection{Server Code}
Things are a little more interesting on the server side. Table \ref{server-run}
shows the code from running a server and table \ref{server-message} shows the
code that handles an incoming message in the server side. Exactly as one would
expect, if not a command, the message is broadcasted to everyone else (i.e.
with the exception of the originating client.)
\begin{table}[!htb]
\lstset{language=C++}
\begin{lstlisting}[frame=single]
void ChatServer::run(port pt)
{
server_->set_connection_handler( this );
server_->set_listener_handler( this );
server_->run(pt);
server_->set_timeouts(ana::FixedTime, ana::time::seconds(10));
std::cout << "Server running, Enter to quit." << std::endl;
std::string s;
std::getline(std::cin, s); //yes, i've seen better code :)
}
\end{lstlisting}
\centering \caption{Running a server.}
\label{server-run}
\end{table}
\begin{table}[!htb]
\lstset{language=C++}
\begin{lstlisting}[frame=single]
void ChatServer::handle_receive( ana::error_code error,
client_id client,
ana::detail::read_buffer buffer)
{
if (! error)
{
std::string msg = buffer->string();
if (msg[0] == '/')
parse_command(client, msg); //interpret the command
else
{
std::stringstream ss;
ss << names_[client] << " : " << msg;
server_->send_if(ana::buffer( ss.str() ), this,
create_predicate( boost::bind(
std::not_equal_to<client_id>(), client, _1) ) );
}
}
else
handle_disconnect(error, client);
}
\end{lstlisting}
\centering \caption{Conditional broadcasting of an incoming message.}
\label{server-message}
\end{table}
\end{document}