-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 sulla rete
-puramente teorica iniziamo con il mostrare un esempio di un client TCP
-elementare. Scopo di questo esempio è fornire un primo approccio alla
-programmazione di rete, tutto questo sarà esaminato in dettaglio nei capitoli
-successivo; qui ci limiteremo a introdurre la nomenclatura senza fornire
-definizioni precise e dettagli di funzionamento che saranno trattati
-estensivamente più avanti.
-
-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 richiesta.
-
-
-\begin{figure}[!htb]
- \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 client elementare per il servizio daytime.}
- \label{fig:net_cli_code}
-\end{figure}
-
-Il sorgente completo del programma (\texttt{ElemDaytimeTCPClient.c}, 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
-\capref{sec:proc_opt_handling}).
-
-Il primo passo (\texttt{\small 14--18}) è creare un \textit{socket} IPv4
-(\texttt{AF\_INET}), di tipo TCP \texttt{SOCK\_STREAM} (in sostanza un canale
-di comunicazione attraverso internet, questi termini verranno spiegati con
-precisione più avanti). La funzione \texttt{socket} 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, per poi inserire il tipo di protocollo e la porta (usando per
-quest'ultima la funzione \texttt{htons} per convertire il formato dell'intero
-usato dal computer 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} sul socket creato in precedenza
-(\texttt{\small 28--32}) si provvede poi a stabilire la connessione con il
-server specificato dall'indirizzo immesso nella struttura passata come secondo
-argomento, il terzo argomento è la dimensione di detta struttura. Dato che
-esistono diversi tipi di socket, si è dovuto effettuare un cast della
-struttura inizializzata in precedenza, che è specifica per i socket IPv4. Un
-valore di ritorno negativo implica il fallimento della connessione.
-
-Completata con successo la connessione il passo successivo (\texttt{\small
- 34--40}) è leggere la data dal socket; il server invierà sempre una stringa
-di 26 caratteri della forma \verb|Wed Apr 4 00:53:00 2001\r\n|, che viene
-letta dalla funzione \texttt{read} e scritta su \texttt{stdout}.
-
-Dato il funzionamento di TCP la risposta potrà tornare in un unico pacchetto
-di 26 byte (come avverrà senz'altro nel caso in questione) ma potrebbe anche
-arrivare in 26 pacchetti di un byte. Per questo nel caso generale non si può
-mai assumere che tutti i dati arrivino con una singola lettura, pertanto
-quest'ultima deve essere effettuata in un loop in cui si continui a leggere
-fintanto che la funzione \texttt{read} non ritorni uno zero (che significa che
-l'altro capo ha chiuso la connessione) o un numero minore di zero (che
-significa un errore nella connessione).
-
-Si noti come in questo caso la fine dei dati sia specificata dal server che
-chiude la connessione; questa è una delle tecniche possibili (è quella usata
-pure dal protocollo HTTP), ma ce ne possono essere altre, ad esempio FTP marca
-la conclusione di un blocco di dati con la sequenza ASCII \verb|\r\n|
-(carriage return e line feed), mentre il DNS mette la lunghezza in testa ad
-ogni blocco che trasmette. Il punto essenziale è che TCP non provvede nessuna
-indicazione che permetta di marcare dei blocchi di dati, per cui se questo è
-necessario deve provvedere il programma stesso.
-
-\subsection{Un primo esempio di server}
-\label{sec:net_serv_sample}
-
-Dopo aver illustrato il client daremo anche un esempio di un server
-elementare, in grado di rispondere al precedente client. Il listato è
-nuovamente mostrato in \nfig, il sorgente completo
-(\texttt{ElemDaytimeTCPServer.c}) è allegato insieme agli altri file nella
-directory \texttt{sources}.
-
-\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 */
-#include <time.h>
-#define MAXLINE 80
-#define BACKLOG 10
-int main(int argc, char *argv[])
-{
-/*
- * Variables definition
- */
- int list_fd, conn_fd;
- int i;
- struct sockaddr_in serv_add;
- char buffer[MAXLINE];
- time_t timeval;
- ...
- /* create socket */
- if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- exit(-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 port is 13 */
- serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
- /* bind socket */
- if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("bind error");
- exit(-1);
- }
- /* listen on socket */
- if (listen(list_fd, BACKLOG) < 0 ) {
- perror("listen error");
- exit(-1);
- }
- /* write daytime to client */
- while (1) {
- if ( (conn_fd = accept(list_fd, (struct sockaddr *) NULL, NULL)) <0 ) {
- perror("accept error");
- exit(-1);
- }
- timeval = time(NULL);
- snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
- if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
- perror("write error");
- exit(-1);
- }
- close(conn_fd);
- }
- /* normal exit */
- exit(0);
-}
- \end{lstlisting}
- \caption{Esempio di codice di un semplice server per il servizio daytime.}
- \label{fig:net_serv_code}
-\end{figure}
+processo figlio (o un \itindex{thread} \textit{thread}) incaricato di fornire
+i servizi richiesti, per porsi immediatamente in attesa di ulteriori
+richieste. In questo modo, con sistemi multitasking, più richieste possono
+essere soddisfatte contemporaneamente. Una volta che il processo figlio ha
+concluso il suo lavoro esso di norma viene terminato, mentre il server
+originale resta sempre attivo.
+
+
+\subsection{Il modello \textit{peer-to-peer}}
+\label{sec:net_peertopeer}
+
+Come abbiamo visto il tratto saliente dell'architettura \textit{client-server}
+è quello della preminenza del server rispetto ai client, le architetture
+\textit{peer-to-peer} si basano su un approccio completamente opposto che è
+quello di non avere nessun programma che svolga un ruolo preminente.
+
+Questo vuol dire che in generale ciascun programma viene ad agire come un nodo
+in una rete potenzialmente paritetica; ciascun programma si trova pertanto a
+ricevere ed inviare richieste ed a ricevere ed inviare risposte, e non c'è più
+la separazione netta dei compiti che si ritrova nelle architetture
+\textit{client-server}.
+
+Le architetture \textit{peer-to-peer} sono salite alla ribalta con
+l'esplosione del fenomeno Napster, ma gli stessi protocolli di routing sono un
+buon esempio di architetture \textit{peer-to-peer}, in cui ciascun nodo,
+tramite il demone che gestisce il routing, richiede ed invia informazioni ad
+altri nodi.
+
+In realtà in molti casi di architetture classificate come \textit{peer-to-peer}
+non è detto che la struttura sia totalmente paritetica e ci sono parecchi
+esempi in cui alcuni servizi vengono centralizzati o distribuiti
+gerarchicamente, come per lo stesso Napster, in cui le ricerche venivano
+effettuate su un server centrale.
+
+
+
+\subsection{Il modello \textit{three-tier}}
+\label{sec:net_three_tier}
+
+Benché qui sia trattato a parte, il modello \textit{three-tier} in realtà è
+una estensione del modello \textit{client-server}. Con il crescere della
+quantità dei servizi forniti in rete (in particolare su internet) ed al numero
+di accessi richiesto. Si è così assistito anche ad una notevole crescita di
+complessità, in cui diversi servizi venivano ad essere integrati fra di loro.
+
+In particolare sempre più spesso si assiste ad una integrazione di servizi di
+database con servizi di web, in cui le pagine vengono costruite dinamicamente
+sulla base dei dati contenuti nel database. In tutti questi casi il problema
+fondamentale di una architettura \textit{client-server} è che la richiesta di
+un servizio da parte di un gran numero di client si scontra con il collo di
+bottiglia dell'accesso diretto ad un unico server, con gravi problemi di
+scalabilità.
+
+Rispondere a queste esigenze di scalabilità il modello più semplice (chiamato
+talvolta \textit{two-tier}) da adottare è stata quello di distribuire il
+carico delle richieste su più server identici, mantenendo quindi
+sostanzialmente inalterata l'architettura \textit{client-server} originale.
+
+Nel far questo ci si scontra però con gravi problemi di manutenibilità dei
+servizi, in particolare per quanto riguarda la sincronizzazione dei dati, e di
+inefficienza dell'uso delle risorse. Il problema è particolarmente grave ad
+esempio per i database che non possono essere replicati e sincronizzati
+facilmente, e che sono molto onerosi, la loro replicazione è costosa e
+complessa.
+
+È a partire da queste problematiche che nasce il modello \textit{three-tier},
+che si struttura, come dice il nome, su tre livelli. Il primo livello, quello
+dei client che eseguono le richieste e gestiscono l'interfaccia con l'utente,
+resta sostanzialmente lo stesso del modello \textit{client-server}, ma la
+parte server viene suddivisa in due livelli, introducendo un
+\textit{middle-tier}, su cui deve appoggiarsi tutta la logica di analisi delle
+richieste dei client per ottimizzare l'accesso al terzo livello, che è quello
+che si limita a fornire i dati dinamici che verranno usati dalla logica
+implementata nel \textit{middle-tier} per eseguire le operazioni richieste dai
+client.
+
+In questo modo si può disaccoppiare la logica dai dati, replicando la prima,
+che è molto meno soggetta a cambiamenti ed evoluzione, e non soffre di
+problemi di sincronizzazione, e centralizzando opportunamente i secondi. In
+questo modo si può distribuire il carico ed accedere in maniera efficiente i
+dati.