\documentclass[10pt,a4paper]{article}
\setlength{\parskip}{1ex}
\setlength{\parindent}{0ex}

% \usepackage{fullpage}
\usepackage[noheadfoot]{geometry}

\usepackage{url}
\usepackage{tp}

\begin{document}
\title{TP de programmation réseau}
\author{Olivier AUBERT}
\date{2003}
\maketitle


\section{Introduction}
\label{sec:references}

Les fichiers d'exemple sont disponibles pour ce TP, à l'adresse
\url{http://www710.univ-lyon1.fr/~oaubert/tp/}. Commencez par aller
récupérer le fichier \texttt{socket.tgz} contenant les exemples et
extrayez les fichiers dans un répertoire approprié.

Où trouver les informations nécessaires pour réaliser ce TP ?

\begin{description}
\item[Manuel] Les pages de manuel (standard sous UNIX) décrivent la
  syntaxe des fonctions utilisées. Pour avoir la syntaxe de la
  commande \texttt{socket}, il faut utiliser \texttt{man 2 socket}. Pour
  avoir des informations plus précises sur les paramètres lors d'une
  connexion IP, il faut utiliser \texttt{man 7 ip}.
  
  Les pages de manuel décrivent notamment : les fichiers d'entête
  (\texttt{.h}) à inclure pour utiliser la fonction, la syntaxe des
  arguments de la fonction et la valeur de retour de la fonction (à
  tester impérativement pour détecter les erreurs).
  
\item[FAQ] Pour des problèmes particuliers sur la programmation des
  sockets, la réponse se trouve probablement dans la FAQ à l'adresse
  \url{http://www.developerweb.net/sock-faq/} (voir plus
  particulièrement les questions triées par catégorie à la fin du
  document).

\end{description}

\section{Côté client}
\label{sec:cote-client}

\subsection{Écriture d'un client TCP simple}
\label{sec:ecriture-dun-client}

On veut écrire un client simple qui va se contenter de lire une ligne
d'information auprès d'un serveur. Par exemple, un service UNIX
standard est le service \emph{daytime} qui retourne la date courante
de l'ordinateur interrogé.

Une manière simple d'interroger ce système est via la commande
\texttt{telnet} sur le port adéquat.

\begin{question}
  Consultez le manuel de telnet pour trouver comment interroger un
  service particulier. Vous pouvez interroger un serveur quelconque,
  ou bien la machine sur laquelle vous êtes connecté en l'appelant
  \texttt{localhost}.
\end{question}

Nous allons écrire un client simple en C qui va effectuer la même
action. Le squelette du code se trouve dans le fichier
\texttt{client-daytime.c}.

Il faut dans un premier temps déterminer le type de protocole que l'on
peut utiliser pour interroger le service. Pour cela, consulter le
fichier \texttt{/etc/services}.

\begin{question}
  Quel est le type de protocole utilisé pour le service
  \emph{daytime}~? Quel est le numéro de port associé~?
\end{question}

\begin{question}
  Où peuvent se poser des problèmes de format des données numériques
  (big endian/little endian)~? Pourquoi n'a-t-on pas utilisé ici de
  fonctions de conversion telles que \texttt{htons} ?
\end{question}

\begin{question}
  Complétez le code du client aux emplacements indiqués par des
  commentaires commençant par \texttt{/* TP:}.
\end{question}

\subsection{Écriture d'un client plus élaboré}
\label{sec:ecriture-dun-client-1}

On va faire évoluer le client précédent vers un autre type de service,
requérant une interaction. Le service \emph{finger} renvoie des
informations sur l'utilisateur d'une machine. 


\begin{question}
  Utilisez \texttt{telnet} pour interroger le service \texttt{finger},
  et comprendre comment il fonctionne (la page de manuel de
  \texttt{finger} peut aider).
\end{question}

\begin{question}
  Extrayez du programme précédent une fonction simple permettant
  d'ouvrir une socket sur la machine et le port précisés.  Le
  squelette de cette fonction se trouve dans le fichier
  \texttt{connexion.c}.
  
  L'interface de la fonction sera
\begin{verbatim}
int connexion-tcp (char* serveur, int port);
\end{verbatim}

  Le port sera transmis dans le codage standard du client, il ne faut
  pas oublier de le convertir dans le codage réseau à l'intérieur de
  la fonction.
  
  La valeur de retour sera le descripteur de socket obtenu, -1 en cas
  d'erreur.
\end{question}

\begin{question}
  En utilisant la fonction ainsi définie, envoyez le nom d'utilisateur
  donné en paramètre au service \emph{finger} et affichez le
  résultat de le requête.
\end{question}

\section{Côté serveur}
\label{sec:cote-serveur}

Nous allons maintenant passer à l'écriture de serveurs, afin d'en
étudier voir le principe.

\subsection{Écriture d'un serveur simple}
\label{sec:ecriture-dun-serveur}

Nous avons écrit un client \emph{daytime}, nous allons à présent en
écrire un serveur. Le serveur va donc attendre une connexion, et
renvoyer la date courante de la machine (fonctions \texttt{time} et
\texttt{ctime}).

\begin{question}
  Utilisez le squelette fourni dans \texttt{serveur-daytime.c} et
  ajoutez les appels nécessaires pour établir la socket, la mettre en
  état d'attente et traiter les connexions.
\end{question}

\begin{question}
  Lancez le serveur sur un port supérieur à 1024 et essayez de
  l'interroger avec la commande \texttt{telnet} ainsi qu'avec le
  client \emph{daytime} écrit précédemment (ce qui peut nécessiter une
  recompilation pour spécifier le numéro de port).
\end{question}

\begin{question}
  Si ce n'est pas déjà fait, isolez la fonction de traitement de la
  connexion dans une fonction à part (\texttt{traite\_requete}).
\end{question}

\subsection{Écriture d'un serveur plus élaboré}
\label{sec:ecriture-dun-serveur-1}

Afin de mettre en évidence les problèmes d'accès concurrent à un même
serveur, on va créer un serveur simpliste d'addition, prenant en
entrée deux nombres et renvoyant leur somme.

\begin{question}
  Modifiez le code du fichier \texttt{serveur-addition.c} pour
  accomplir la tâche précisée.
\end{question}

\begin{question}
  Connectez-vous au serveur indiqué via la commande \texttt{telnet} et
  testez le bon fonctionnement du serveur.
\end{question}

\begin{question}
  Lancez depuis plusieurs terminaux plusieurs connexions simultanées
  vers le même serveur d'addition. Qu'observez-vous ?
\end{question}

\subsection{Écriture d'un serveur multi-connexions}
\label{sec:ecriture-dun-serveur-2}

Il existe plusieurs manières de gérer le problème des connexions
concurrentes.  Nous allons en voir la plus commune ici. Elle consiste
à créer un nouveau processus (fonction \texttt{fork}) pour chaque
nouvelle connexion. Le fils va alors traiter la requête (fonction
\texttt{traite\_requete}), tandis que le père va simplement fermer la
socket de connexion et se remettre en situation d'attente.

\begin{question}
  Modifiez le code de \texttt{serveur-addition2.c} de manière à créer
  un nouveau processus pour gérer chaque nouvelle connexion.
\end{question}

\begin{question}
  Lancez depuis plusieurs terminaux plusieurs connexions simultanées
  vers le nouveau serveur d'addition.
\end{question}

\end{document}
