Inserito il package listings ... e adesso ho la syntax highlight dei
[gapil.git] / network.tex
index 3782f81e2f6e4015927e9db5384c6d26584b63ab..3a72f11f1f9649d6c536204bc30c94d8028afcb4 100644 (file)
@@ -6,9 +6,164 @@ come prerequisiti per capire la programmazione di rete ed esamineremo a grandi
 linee i protocolli di rete e come questi sono organizzati e interagiscono.
 
 In particolare, avendo assunto l'ottica di un'introduzione mirata alla
-programmazione di rete, ci concentreremo sul protocollo più diffuso che è
-quello che sta alla base di internet, ed in particolare sulle parti più
-importanti ai fini della programmazione.  
+programmazione, ci concentreremo sul protocollo più diffuso che è quello che
+sta alla base di internet, ed in particolare sulle parti più importanti ai
+fini della programmazione. 
+
+
+\section{Il modello client-server}
+\label{sec:net_cliserv}.
+
+La differenza principale fra un'applicazione di rete e un programma normale è
+che quest'ultima per definizione concerne la comunicazione fra ``processi''
+diversi (che in generale non girano neanche sulla stessa macchina). Questo già
+prefigura un cambiamento completo rispetto all'ottica del ``programma''
+monolitico all'interno del quale vengono eseguite tutte le istruzioni, e
+presuppone un sistema operativo ``multitasking'' in grado di eseguire processi
+diversi.
+
+Il concetto fondamentale si basa la programmazione di rete sotto Linux (e
+sotto Unix in generale) è il modello \textit{client-server} in cui un
+programma di servizio, il \textit{server} riceve un connessione e risponde a
+un programma di utilizzo, il \textit{client}, provvedendo a quest'ultimo un
+definito insieme di servizi.
+
+Esempi di questo modello sono il WEB, ftp, telnet, ssh e praticamente ogni
+servizio che viene fornito tramite la rete, ma il modello è utilizzato in
+generale anche per programmi che non fanno necessariamente uso della rete,
+come il sistema a finestre.
+
+Normalmente si dividono i server in due categorie principali,
+\textit{concorrenti} e \textit{iterativi}, sulla base del loro comportamento.
+
+Un server iterativo risponde alla richiesta inviando i dati e resta occupato
+(non rispondendo ad ulteriori richieste) fintanto che non ha concluso la
+richiesta. Una volta completata la richiesta il server diventa di nuovo
+disponibile.
+
+Un server concorrente al momento di trattare la richiesta crea un processo
+figlio incaricato di fornire i servizi richiesti, per poi porsi in attesa di
+ulteriori richieste. In questo modo più richieste possono essere soddisfatte
+contemporaneamente, una volta che il processo figlio ha concluso il suo lavoro
+viene terminato, mentre il server originale resta sempre attivo.
+
+
+\subsection{Un primo esempio di client}
+\label{sec:net_cli_sample}
+
+Per evitare di rendere l'esposizione dei concetti generali puramente teorica
+iniziamo con il mostrare un semplice esempio di client TCP.  In \nfig è
+riportata la sezione principale del codice del nostro client elementare per il
+servizio \textit{daytime}, un servizio standard che restituisce l'ora locale
+della macchina a cui si effettua la richesta.
+
+\begin{figure}[htbp]
+  \footnotesize
+  \begin{lstlisting}{}
+#include <sys/types.h>   /* predefined types */
+#include <unistd.h>      /* include unix standard library */
+#include <arpa/inet.h>   /* IP addresses conversion utiliites */
+#include <sys/socket.h>  /* socket library */
+#include <stdio.h>       /* include standard I/O library */
+
+int main(int argc, char *argv[])
+{
+    int sock_fd;
+    int i, nread;
+    struct sockaddr_in serv_add;
+    char buffer[MAXLINE];
+     ...
+    /* create socket */
+    if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+        perror("Socket creation error");
+        return -1;
+    }
+    /* initialize address */
+    memset((void *) &serv_add, 0, sizeof(serv_add)); /* clear server address */
+    serv_add.sin_family = AF_INET;                   /* address type is INET */
+    serv_add.sin_port = htons(13);                   /* daytime post is 13 */
+    /* build address using inet_pton */
+    if ( (inet_pton(AF_INET, argv[optind], &serv_add.sin_addr)) <= 0) {
+        perror("Address creation error");
+        return -1;
+    }
+    /* extablish connection */
+    if (connect(sock_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
+        perror("Connection error");
+        return -1;
+    }
+    /* read daytime from server */
+    while ( (nread = read(sock_fd, buffer, MAXLINE)) > 0) {
+        buffer[nread]=0;
+        if (fputs(buffer, stdout) == EOF) {          /* write daytime */
+            perror("fputs error");
+            return -1;
+        }
+    }
+    /* error on read */
+    if (nread < 0) {
+        perror("Read error");
+        return -1;
+    }
+    /* normal exit */
+    return 0;
+}
+  \end{lstlisting}
+  \caption{Esempio di codice di un semplice client per il servizio daytime.}
+  \label{fig:net_cli_code}
+\end{figure}
+
+
+Scopo di questo esempio è fornire un primo approccio alla programmazione di
+rete, per questo motivo non ci dilungheremo nel trattare il significato dei
+termini o il funzionamento delle varie funzioni utilizzate. Tutto questo sarà
+esaminato in dettaglio nel seguito, per cui qui ci limiteremo a citarli senza
+ulteriori spiegazioni.
+
+Il listato completo del programma (che comprende il trattamento delle opzioni
+e una funzione per stampare un messaggio di aiuto) è allegato alla guida nella
+sezione dei codici sorgente e può essere compilato su una qualunque macchina
+linux.
+
+Il programma anzitutto include gli header necessari (\texttt{\small 1--5});
+dopo la dichiarazione delle variabili (\texttt{\small 9--12}), si è omessa
+tutta la parte relativa al trattamento degli argomenti passati dalla linea di
+comando effettuata con le apposite routines illustrate in
+\ref{cha:parameter_options}.
+
+Il primo passo (\texttt{\small 14--18}è creare un \textit{socket} internet
+(\texttt{AF\_INET}), di tipo TCP \texttt{SOCK\_STREAM}), la funzione ritorna
+un descrittore, analogo a quello dei file, che viene usato per identificare il
+socket in tutte le chiamate successive. Nel caso la chiamata fallisca si
+stampa un errore con la relativa routine e si esce.
+
+Il passo seguente (\texttt{\small 19--27}) è quello di costruire una apposita
+struttura \texttt{sockaddr\_in} in cui sarà inserito l'indirizzo del server ed
+il numero della porta del servizio. Il primo passo è inizializzare tutto a
+zero, poi si setta il tipo di protocollo e la porta (usando la funzione
+\texttt{htons} per convertire il formato dell'intero a quello usato nella
+rete), infine si utilizza la funzione \texttt{inet\_pton} per convertire
+l'indirizzo numerico passato dalla linea di comando.
+
+Usando la funzione \texttt{connect} (\texttt{\small 28--32}) si provvede poi a
+stabilire la connessione con il server. Un valore negativo 
+
+\subsection{Un primo esempio di server}
+\label{sec:net_serv_sample}
+
+Dopo aver visto il client facciamo vedere adesso anche il corrispettivo
+server, in questo modo sarà possibile fare delle prove 
+
+\begin{figure}[htbp]
+  \begin{center}
+    \begin{verbatim}
+
+
+    \end{verbatim}
+    \caption{Esempio di codice di un semplice server per il servizio daytime.}
+    \label{fig:net_serv_code}
+  \end{center}
+\end{figure}
 
 
 \section{I protocolli di rete}
@@ -190,6 +345,12 @@ rete (locale) a basso livello, un uso quindi molto specialistico. Il livello 1
 invece dipende dalle singole applicazioni ed è di nuovo troppo specifico per
 essere affrontato qui.
 
+In questa sezione daremo una breve descrizione dei vari protocolli di TCP/IP,
+ma ci concentreremo principalmente sul livello di trasposto e in particolare
+sul protocollo TCP sia per il ruolo centrale che esso svolge nella maggior
+parte delle applciazioni, sia per la sua complessità che necessita di maggiori
+spiegazioni.
+
 \subsection{Il quadro generale}
 
 Benché si parli di TCP/IP questa famiglia di protocolli è composta anche da
@@ -280,8 +441,8 @@ internet ha iniziato a far emergere i vari limiti di IPv4, per risolverne i
 problemi si è perciò definita una nuova versione del protocollo, che (saltando
 un numero) è diventata la versione 6. IPv6 nasce quindi come evoluzione di
 IPv4, mantendone inalterate le funzioni che si sono dimostrate valide,
-eliminando quelle inutili e aggiungendone poche altre ponendo al contempo una
-grande attenzione a mantenere il protocollo il più snello e veloce possibile.
+eliminando quelle inutili e aggiungendone poche altre per mantenere il
+protocollo il più snello e veloce possibile.
 
 I cambiamenti apportati sono comunque notevoli e si possono essere riassunti a
 grandi linee nei seguenti punti:
@@ -312,44 +473,120 @@ Per maggiori dettagli riguardo al protocollo si pu
 \subsection{UDP: User Datagram Protocol)}
 \label{sec:net_udp}
 
+UDP è un protocollo di trasporto molto semplice, la sua descizione completa è
+contenuta dell'RFC~768, ma in sostanza esso è una semplice interfaccia a IP dal
+livello di trasporto. Quando un'applicazione usa UDP essa scrive un pacchetto
+di dati (il cosiddetto \textit{datagram} che da il nome al protocollo) su un
+socket, al pacchetto viene aggiunto un header molto semplice (per una
+descrizione più accurata vedi \ref{sec:appA_udp}), e poi viene passato al
+livello superiore (IPv4 o IPv6 che sia) che lo spedisce verso la destinazione.
+Dato che né IPv4 né IPv6 garantiscono l'affidabilità niente assicura che il
+pacchetto arrivi a destinazione, né che più pacchetti arrivino nello stesso
+ordine in cui sono stati spediti.
+
+Pertanto il problema principale che si affronta quando si usa UDP è la
+mancanza di affidabilità, se si vuole essere sicuri che i pacchetti arrivino a
+destinazione occorrerà provvedere con l'applicazione all'interno della quale
+si dovrà inserire tutto quanto necessario a gestire la notifica di
+ricevimento, la ritrasmissione, il timeout. 
+
+Si tenga conto poi che in UDP niente garantisce che i pacchetti arrivino nello
+stesso ordine in cui sono stati trasmessi, e può anche accadere che i
+pacchetti vengano duplicati nella trasmissione, e non solo perduti. Di tutto
+questo di nuovo deve tenere conto l'applicazione.
+
+Un'altro aspetto di UDP è che se un pacchetto raggiunge correttamente la
+destinazione esso viene passato all'applicazione ricevente in tutta la sua
+lunghezza, la trasmissione avviene perciò per \textit{record} la cui lunghezza
+viene anche essa trasmessa all'applicazione all'atto del ricevimento.
+
+Infine UDP è un protocollo che opera senza connessione
+(\textit{connectionless}) in quanto non è necessario stabilire nessun tipo di
+relazione tra origine e destinazione dei pacchetti. Si hanno così situazioni
+in cui un client può scrivere su uno stesso socket pacchetti destinati a
+server diversi, o un server ricevere su un socket paccetti provenienti da
+client diversi.  Il modo più semplice di immaginarsi il funzionamento di UDP è
+quello della radio, in cui si può ``trasmettere a'' e ``ricevere da'' più
+stazioni usando la stessa frequenza.
+
+Nonostante gli evidenti svantaggi comportati dall'inaffidabilità UDP ha il
+grande pregio della velocità che in certi casi è essenziale; inoltre si presta
+bene per le applicazioni in cui la connessione non è necessaria e
+costituirebbe solo un peso di prestazioni mentre una perdita di pacchetti può
+essere tollerata, come quelle che usano il multicasting.
 
 \subsection{TCP: Transport Control Protocol)}
 \label{sec:net_tcp}
 
+Il TCP è un protocollo molto complesso, definito nell'RFC~739 e completamente
+diverso da UDP; alla base del suo design infatti non stanno semplicità e
+velocità, ma la ricerca della massima affidabilità possibile nella
+trasmissione dei dati.
+
+La prima differenza con UDP è che TCP provvede sempre una conessione diretta
+fra un client e un server, attraverso la quale essi possono comunicare; per
+questo il paragone più appropriato per questo protocollo è quello del
+collegamento telefonico, in quanto prima viene stabilita una connessione fra
+due stazioni su cui poi viene effettuata una comunicazione diretta.
+
+Caratteristica fondamentale di TCP è l'affidabilità; quando i dati vengono
+inviati attraverso una connessione ne viene richiesto un ``ricevuto''
+(il cosiddetto \textit{acknowlegment}), se questo non arriva essi verranno
+ritrasmessi facendo un determinato numero di tentativi intervallati da un
+periodo di tempo crescente, fintanto che la connessione sarà considerata
+fallita o caduta la connessione (con un errore di \textit{time-out}), dopo un
+periodo di tempo che dipende dall'implementazione e che può variare far i
+quattro e i dieci minuti.
+
+Inoltre per tenere conto delle diverse condizioni in cui può trovarsi la linea
+di comunicazione TCP comprende anche un algoritmo di calcolo dinamico del
+tempo di andata e ritorno dei pacchetti (il cosiddetto RTT, 
+\textit{round-trip time}) fra un client e un server che lo rende in grado di
+adattarsi alle condizioni della rete per non generare inutili ritrasmissioni o
+cadere facilmente in timeout.
+
+Inoltre TCP è in grado di preservare l'ordine dei dati assegnando un numero di
+sequenza ad ogni byte che trasmette. Ad esempio se un'applicazione scrive 3000
+bytes su un socket TCP, questi potranno essere spezzati dal protocollo in due
+segmenti (le unità di dati passate da TCP a IP vengono chiamate
+\textit{segment}) di 1500 bytes, di cui il primo conterrà il numero di
+sequenza $1-1500$ e il secondo il numero $1501-3000$. In questo modo anche se
+i segmenti arrivano a destinazione in un ordine diverso, o se alcuni arrivano
+più volte a causa di ritrasmissioni dovute alla perdita dei ricevuto,
+all'arrivo sarà comunque possibile riordinare i dati e scartare i duplicati.
+
+Il protocollo provvede anche un controllo di flusso (\textit{flow control}),
+cioè specifica sempre all'altro capo della trasmissione quanti dati può
+ricevere tramite una \textit{advertised window} (letteralmente finestra
+annunciata), che indica lo spazio disponibile nel buffer di ricezione,
+cosicchè nella trasmissione non vengano inviati più dati di quelli che possono
+essere ricevuti. 
+
+Questa finestra cambia dinamicamente diminuendo con la ricezione dei dati dal
+socket ed aumentando con la lettura di quest'ultimo da parte
+dell'applicazione, se diventa nulla il buffer di ricezione è pieno e non
+verranno accettati altri dati.  Si noti che UDP non provvede niente di tutto
+ciò per cui nulla impedisce che vengano trasmessi pacchetti ad un rate che il
+ricevitore non può sostenere.
+
+Infine attraverso TCP la trasmissione è sempre bidirezionale (in inglese
+\textit{full-duplex}), è cioè possibile sia trasmettere che ricevere allo
+stesso tempo, il che poi comporta che quanto dicevamo a proposito del
+controllo di flusso e della gestione della sequenzialità dei dati viene
+effettuato per entrambe le direzioni di comunicazione.
+
+
+
+\subsection{Creazione e terminazione della connessione TCP}
+
+Per capire il funzionamento delle funzioni della interfaccia dei socket che
+operano con TCP (come \texttt{connect}, \texttt{accept} e \texttt{close} che
+vedremo più avanti) è fodamentale capire come funziona la creazione e la
+conclusione di una connessione TCP.
+
+
+
+
+\subsection{Le porte}
 
 
-\section{Il modello client-server}
-\label{sec:net_cliserv}.
-
-La differenza principale fra un'applicazione di rete e un programma normale
-è che quest'ultima per definizione concerne la comunicazione fra
-``processi'' diversi (che in generale non girano neanche sulla stessa
-macchina). Questo già prefigura un cambiamento completo rispetto all'ottica
-del ``programma'' monolitico all'interno del quale vengono eseguite tutte le
-istruzioni, e presuppone un sistema operativo ``multitasking'' in grado di
-eseguire processi diversi.
-
-Il concetto fondamentale si basa la programmazione di rete sotto Linux (e
-sotto Unix in generale) è il modello \textit{client-server} in cui un
-programma di servizio, il \textit{server} riceve un connessione e risponde a
-un programma di utilizzo, il \textit{client}, provvedendo a quest'ultimo un
-definito insieme di servizi.
-
-Esempi di questo modello sono il WEB, ftp, telnet, ssh e praticamente ogni
-servizio che viene fornito tramite la rete, ma il modello è utilizzato in
-generale anche per programmi di uso locale.
-
-Normalmente si dividono i server in due categorie principali,
-\textit{concorrenti} e \textit{iterativi}, sulla base del loro comportamento.
-
-Un server iterativo risponde alla richiesta inviando i dati e resta occupato
-(non rispondendo ad ulteriori richieste) fintanto che non ha concluso la
-richiesta. Una volta completata la richiesta il server diventa di nuovo
-disponibile.
-
-Un server concorrente al momento di trattare la richiesta crea un processo
-figlio incaricato di fornire i servizi richiesti, per poi porsi in attesa di
-ulteriori richieste. In questo modo più richieste possono essere soddisfatte
-contemporaneamente, una volta che il processo figlio ha concluso il suo lavoro
-viene terminato, mentre il server originale resta sempre attivo.
-