\label{cha:elem_TCP_sock}
In questo capitolo iniziamo ad approfondire la conoscenza dei socket TCP,
-tratteremo qui dunque il funzionamento delle varie funzioni che si sono usate
-nei due esempi elementari forniti in precedenza (vedi
-\secref{sec:net_cli_sample} e \secref{sec:net_serv_sample}), previa una
-descrizione delle principali caratteristiche del funzionamento di una
-connessione TCP.
+tratteremo qui dunque le varie funzioni che si sono usate nei due esempi
+elementari forniti nel capitolo precedente (vedi \secref{sec:net_cli_sample} e
+\secref{sec:net_serv_sample}), previa una descrizione delle principali
+caratteristiche del funzionamento di una connessione TCP.
\section{Il funzionamento di una connessione TCP}
\label{sec:TCPel_connession}
Prima di entrare nei dettagli delle funzioni usate nelle applicazioni che
-utilizzano i socket TCP, è fondamentale spiegare alcune basi del funzionamento
-del TCP; la conoscenza del funzionamento del protocollo è infatti essenziale
-per capire il modello di programmazione ed il funzionamento delle API.
-
-In particolare ci concentreremo sulle modalità con le quali il protocollo dà
-inizio e conclude una connessione; faremo inoltre anche un breve accenno al
-significato di alcuni dei vari stati che il protocollo assume durante la vita
-di una connessione, che possono essere osservati per ciascun
-socket\index{socket} attivo con l'uso del programma \cmd{netstat}.
+utilizzano i socket TCP, è fondamentale spiegare alcune delle basi del
+funzionamento del protocollo poiché questa conoscenza è essenziale per
+comprendere il comportamento di dette funzioni per questi socket, ed il
+relativo modello di programmazione.
+
+Il protocollo TCP serve a creare degli \textit{stream socket}, cioè un canale
+di comunicazione che stabilisce una connessione fra due stazioni, in modo che
+queste possano scambiarsi i dati. In questo capitolo ci concentreremo sulle
+modalità con le quali il protocollo dà inizio e conclude una connessione e
+faremo inoltre un breve accenno al significato di alcuni dei vari stati che
+questa viene ad assumere durante la sua vita.
\subsection{La creazione della connessione: il \textit{three way handshake}}
\label{sec:TCPel_conn_cre}
\textsl{apertura attiva}, dall'inglese \textit{active open}. La chiamata di
\func{connect} blocca il processo e causa l'invio da parte del client di un
segmento SYN,\footnote{Si ricordi che il segmento è l'unità elementare di
- dati trasmessa dal protocollo TCP al livello superiore; tutti i segmenti
+ dati trasmessa dal protocollo TCP al livello successivo; tutti i segmenti
hanno un header che contiene le informazioni che servono allo
\textit{stack TCP} (così viene di solito chiamata la parte del kernel che
implementa il protocollo) per realizzare la comunicazione, fra questi dati
indicare un massimo di 65535 byte (anche se Linux usa come massimo 32767 per
evitare problemi con alcuni stack bacati che usano l'aritmetica con segno
per implementare lo stack TCP); ma alcuni tipi di connessione come quelle ad
- alta velocità (sopra i 45Mbits/sec) e quelle che hanno grandi ritardi nel
+ alta velocità (sopra i 45Mbit/sec) e quelle che hanno grandi ritardi nel
cammino dei pacchetti (come i satelliti) richiedono una finestra più grande
per poter ottenere il massimo dalla trasmissione, per questo esiste questa
opzione che indica un fattore di scala da applicare al valore della finestra
attiva prevede come negoziazione che l'altro capo della connessione
riconosca esplicitamente l'opzione inserendola anche lui nel suo SYN di
risposta dell'apertura della connessione.} per la connessione corrente
- (espresso come numero di bit cui shiftare a sinistra il valore della
+ (espresso come numero di bit cui spostare a sinistra il valore della
finestra annunciata inserito nel pacchetto).
\item \textit{timestamp option}, è anche questa una nuova opzione necessaria
Come riportato da Stevens in \cite{UNP1} lo stato \texttt{TIME\_WAIT} è
probabilmente uno degli aspetti meno compresi del protocollo TCP, è infatti
-comune trovare nei newsgroup domande su come sia possibile evitare che
-un'applicazione resti in questo stato lasciando attiva una connessione ormai
-conclusa; la risposta è che non deve essere fatto, ed il motivo cercheremo di
-spiegarlo adesso.
+comune trovare domande su come sia possibile evitare che un'applicazione resti
+in questo stato lasciando attiva una connessione ormai conclusa; la risposta è
+che non deve essere fatto, ed il motivo cercheremo di spiegarlo adesso.
Come si è visto nell'esempio precedente (vedi \figref{fig:TPCel_conn_example})
\texttt{TIME\_WAIT} è lo stato finale in cui il capo di una connessione che
sulla rete; questo tempo è limitato perché ogni pacchetto IP può essere
ritrasmesso dai router un numero massimo di volte (detto \textit{hop limit}).
Il numero di ritrasmissioni consentito è indicato dal campo TTL dell'header di
-IP (per maggiori dettagli vedi \secref{sec:IP_xxx}), e viene decrementato
-ad ogni passaggio da un router; quando si annulla il pacchetto viene scartato.
-Siccome il numero è ad 8 bit il numero massimo di ``salti'' è di 255, pertanto
-anche se il TTL (da \textit{time to live}) non è propriamente un limite sul
-tempo di vita, si stima che un pacchetto IP non possa restare nella rete per
-più di MSL secondi.
+IP (per maggiori dettagli vedi \secref{sec:IP_xxx}), e viene decrementato ad
+ogni passaggio da un router; quando si annulla il pacchetto viene scartato.
+Siccome il numero è ad 8 bit il numero massimo di ``\textsl{salti}'' è di 255,
+pertanto anche se il TTL (da \textit{time to live}) non è propriamente un
+limite sul tempo di vita, si stima che un pacchetto IP non possa restare nella
+rete per più di MSL secondi.
Ogni implementazione del TCP deve scegliere un valore per la MSL (l'RFC~1122
raccomanda 2 minuti, Linux usa 30 secondi), questo comporta una durata dello
\const{INADDR\_ANY}, il cui valore, come visto anche negli esempi precedenti
è pari a zero, nell'esempio \figref{fig:net_serv_code} si è usata
un'assegnazione immediata del tipo:
-
-\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
-serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
-\end{lstlisting}
+\includecodesnip{listati/serv_addr_sin_addr.c}
Si noti che si è usato \func{htonl} per assegnare il valore
\const{INADDR\_ANY}, benché essendo questo pari a zero il riordinamento sia
\const{in6addr\_any} (dichiarata come \direct{extern}, ed inizializzata dal
sistema al valore \const{IN6ADRR\_ANY\_INIT}) che permette di effettuare una
assegnazione del tipo:
+\includecodesnip{listati/serv_addr_sin6_addr.c}
+in maniera analoga si può utilizzare la variabile \const{in6addr\_loopback}
+per indicare l'indirizzo di \textit{loopback}, che a sua volta viene
+inizializzata staticamente a \const{IN6ADRR\_LOOPBACK\_INIT}.
-\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
-serv_add.sin6_addr = in6addr_any; /* connect from anywhere */
-\end{lstlisting}
\subsection{La funzione \func{connect}}
socket \param{sockfd}. Quest'ultimo (detto \textit{listening socket}) è quello
creato all'inizio e messo in ascolto con \func{listen}, e non viene toccato
dalla funzione. Se non ci sono connessioni pendenti da accettare la funzione
-mette in attesa il processo\footnote{a meno che non si sia imopstato il socket
+mette in attesa il processo\footnote{a meno che non si sia impostato il socket
per essere non bloccante (vedi \secref{sec:file_noblocking}), nel qual caso
ritorna con l'errore \errcode{EAGAIN}. Torneremo su questa modalità di
operazione in \secref{sec:xxx_sock_noblock}.} fintanto che non ne arriva
\file{ElemDaytimeTCPCuncServ.c} è allegato nella directory dei sorgenti.
\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 */
-#include <time.h>
-
-int main(int argc, char *argv[])
-{
- int list_fd, conn_fd;
- int i;
- struct sockaddr_in serv_add, client;
- char buffer[MAXLINE];
- socklen_t len;
- time_t timeval;
- pid_t pid;
- int logging=0;
- ...
- /* write daytime to client */
- while (1) {
- if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len))
- <0 ) {
- perror("accept error");
- exit(-1);
- }
- /* fork to handle connection */
- if ( (pid = fork()) < 0 ){
- perror("fork error");
- exit(-1);
- }
- if (pid == 0) { /* child */
- close(list_fd);
- 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);
- }
- if (logging) {
- inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
- printf("Request from host %s, port %d\n", buffer,
- ntohs(client.sin_port));
- }
- close(conn_fd);
- exit(0);
- } else { /* parent */
- close(conn_fd);
- }
- }
- /* normal exit, never reached */
- exit(0);
-}
- \end{lstlisting}
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includecodesample{listati/ElemDaytimeTCPCuncServ.c}
+ \end{minipage}
+ \normalsize
\caption{Esempio di codice di un server concorrente elementare per il
servizio daytime.}
\label{fig:TCPel_serv_code}
\subsection{Le funzioni \func{getsockname} e \func{getpeername}}
\label{sec:TCPel_get_names}
-Queste due funzioni vengono usate per ottenere i dati realtivi alla socket
+Queste due funzioni vengono usate per ottenere i dati relativi alla socket
pair associata ad un certo socket; la prima è \funcd{getsockname} e
restituisce l'indirizzo locale; il suo prototipo è:
\begin{prototype}{sys/socket.h}