sistema cioè deve provvedere ad organizzare e rendere accessibile in maniera
opportuna l'informazione tenuta sullo spazio grezzo disponibile sui dischi.
Questo viene fatto strutturando l'informazione sul disco attraverso quello che
-si chiama un \textit{filesystem} (vedi \ref{sec:file_arch_func}), essa poi
-viene resa disponibile ai processi attraverso quello che viene chiamato il
+si chiama un \textit{filesystem} (vedi sez.~\ref{sec:file_arch_func}), essa
+poi viene resa disponibile ai processi attraverso quello che viene chiamato il
\textsl{montaggio} del \textit{filesystem}.
-% (approfondiremo tutto ciò in \secref{sec:file_arch_func}).
+% (approfondiremo tutto ciò in sez.~\ref{sec:file_arch_func}).
In questa sezione faremo una panoramica generica su come il sistema presenta
i file ai processi, trattando l'organizzazione di file e directory, i tipi di
stesso, ma anche essi devono essere montati all'interno dell'albero dei file.
Una directory, come vedremo in maggior dettaglio in
-\secref{sec:file_vfs_work}, è anch'essa un file, solo che è un file
+sez.~\ref{sec:file_vfs_work}, è anch'essa un file, solo che è un file
particolare che il kernel riconosce come tale. Il suo scopo è quello di
contenere una lista di nomi di file e le informazioni che associano ciascun
nome al contenuto. Dato che questi nomi possono corrispondere ad un qualunque
costrutto \file{//} viene considerato equivalente a \file{/}.}: ovviamente,
perché il procedimento funzioni, occorre che i nomi indicati come directory
esistano e siano effettivamente directory, inoltre i permessi (si veda
-\secref{sec:file_access_control}) devono consentire l'accesso all'intero
+sez.~\ref{sec:file_access_control}) devono consentire l'accesso all'intero
\textit{pathname}.
Se il \textit{pathname}\index{pathname} comincia per \file{/} la ricerca parte
dalla directory radice del processo; questa, a meno di un \func{chroot} (su
-cui torneremo in \secref{sec:file_chroot}) è la stessa per tutti i processi ed
-equivale alla directory radice dell'albero dei file: in questo caso si parla
-di un \textsl{pathname assoluto}\index{pathname!assoluto}. Altrimenti la
+cui torneremo in sez.~\ref{sec:file_chroot}) è la stessa per tutti i processi
+ed equivale alla directory radice dell'albero dei file: in questo caso si
+parla di un \textsl{pathname assoluto}\index{pathname!assoluto}. Altrimenti la
ricerca parte dalla directory corrente (su cui torneremo in
-\secref{sec:file_work_dir}) ed il pathname è detto \textsl{pathname
+sez.~\ref{sec:file_work_dir}) ed il pathname è detto \textsl{pathname
relativo}\index{pathname!relativo}.
I nomi \file{.} e \file{..} hanno un significato speciale e vengono inseriti
Come detto in precedenza, in Unix esistono vari tipi di file; in Linux questi
sono implementati come oggetti del \textit{Virtual File System} (vedi
-\secref{sec:file_vfs_work}) e sono presenti in tutti i filesystem unix-like
+sez.~\ref{sec:file_vfs_work}) e sono presenti in tutti i filesystem unix-like
utilizzabili con Linux. L'elenco dei vari tipi di file definiti dal
\textit{Virtual File System}\index{Virtual File System} è riportato in
-\tabref{tab:file_file_types}.
+tab.~\ref{tab:file_file_types}.
Si tenga ben presente che questa classificazione non ha nulla a che fare con
la classificazione dei file (che in questo caso sono sempre file di dati) in
base al loro contenuto, o tipo di accesso. Essa riguarda invece il tipo di
oggetti; in particolare è da notare la presenza dei cosiddetti file speciali.
Alcuni di essi, come le \textit{fifo} (che tratteremo in
-\secref{sec:ipc_named_pipe}) ed i \textit{socket}\index{socket} (che
-tratteremo in \capref{cha:socket_intro}) non sono altro che dei riferimenti
+sez.~\ref{sec:ipc_named_pipe}) ed i \textit{socket}\index{socket} (che
+tratteremo in cap.~\ref{cha:socket_intro}) non sono altro che dei riferimenti
per utilizzare delle funzionalità di comunicazione fornite dal kernel. Gli
altri sono i \textsl{file di dispositivo}\index{file!di dispositivo} (o
\textit{device file}) che costituiscono una interfaccia diretta per leggere e
un file che contiene dei dati (l'accezione normale di file) \\
\textit{directory} & \textsl{cartella o direttorio} &
un file che contiene una lista di nomi associati a degli
- \textit{inode}\index{inode} (vedi \secref{sec:file_vfs}). \\
+ \textit{inode}\index{inode} (vedi sez.~\ref{sec:file_vfs}). \\
\textit{symbolic link} & \textsl{collegamento simbolico} &
un file che contiene un riferimento ad un altro file/directory \\
\textit{char device} & \textsl{dispositivo a caratteri} &
un file che identifica una periferica ad accesso a blocchi \\
\textit{fifo} & ``\textsl{coda}'' &
un file speciale che identifica una linea di comunicazione software
- unidirezionale (vedi \secref{sec:ipc_named_pipe}).\\
+ unidirezionale (vedi sez.~\ref{sec:ipc_named_pipe}).\\
\textit{socket}\index{socket} & ``\textsl{presa}''&
un file speciale che identifica una linea di comunicazione software
- bidirezionale (vedi \capref{cha:socket_intro}) \\
+ bidirezionale (vedi cap.~\ref{cha:socket_intro}) \\
\hline
\end{tabular}
\caption{Tipologia dei file definiti nel VFS}
accedere al loro contenuto.
La prima è l'interfaccia standard di Unix, quella che il manuale delle
-\acr{glibc} chiama interfaccia dei descrittori di file (o \textit{file
- descriptor}). È un'interfaccia specifica dei sistemi unix-like e fornisce
+\textsl{glibc} chiama interfaccia dei descrittori di file (o \textit{file
+ descriptor}). È un'interfaccia specifica dei sistemi unix-like e fornisce
un accesso non bufferizzato; la tratteremo in dettaglio in
-\capref{cha:file_unix_interface}.
+cap.~\ref{cha:file_unix_interface}.
L'interfaccia è primitiva ed essenziale, l'accesso viene detto non
bufferizzato in quanto la lettura e la scrittura vengono eseguite chiamando
La seconda interfaccia è quella che il manuale della \acr{glibc} chiama degli
\textit{stream}\index{file!stream}. Essa fornisce funzioni più evolute e un
accesso bufferizzato (controllato dalla implementazione fatta dalle
-\acr{glibc}), la tratteremo in dettaglio nel \capref{cha:files_std_interface}.
+\acr{glibc}), la tratteremo in dettaglio nel
+cap.~\ref{cha:files_std_interface}.
Questa è l'interfaccia standard specificata dall'ANSI C e perciò si trova
anche su tutti i sistemi non Unix. Gli \textit{stream}\index{file!stream} sono
Entrambe le interfacce possono essere usate per l'accesso ai file come agli
altri oggetti del VFS (fifo, socket\index{socket}, device, sui quali torneremo
in dettaglio a tempo opportuno), ma per poter accedere alle operazioni di
-controllo (descritte in \secref{sec:file_fcntl} e \secref{sec:file_ioctl}) su
-un qualunque tipo di oggetto del VFS occorre usare l'interfaccia standard di
-Unix con i \textit{file descriptor}. Allo stesso modo devono essere usati i
+controllo (descritte in sez.~\ref{sec:file_fcntl} e sez.~\ref{sec:file_ioctl})
+su un qualunque tipo di oggetto del VFS occorre usare l'interfaccia standard
+di Unix con i \textit{file descriptor}. Allo stesso modo devono essere usati i
\textit{file descriptor}\index{file!descriptor} se si vuole ricorrere a
modalità speciali di I/O come il \textit{file locking}\index{file!locking} o
-l'I/O non-bloccante (vedi \capref{cha:file_advanced}).
+l'I/O non-bloccante (vedi cap.~\ref{cha:file_advanced}).
Gli \textit{stream} forniscono un'interfaccia di alto livello costruita sopra
quella dei \textit{file descriptor}, che permette di poter scegliere tra
% cancellato da un altro processo, sarà sempre possibile mantenere l'accesso ai
% dati, e lo spazio su disco non verrà rilasciato fintanto che il file non sarà
% chiuso e l'ultimo riferimento cancellato. È pertanto possibile (come vedremo
-% in dettaglio in \secref{sec:file_link}) aprire un file provvisorio per
+% in dettaglio in sez.~\ref{sec:file_link}) aprire un file provvisorio per
% cancellarlo immediatamente dopo; in questo modo all'uscita del programma il
% file scomparirà definitivamente dal disco, ma il file ed il suo contenuto
% saranno disponibili per tutto il tempo in cui il processo è attivo.
-% Ritorneremo su questo più avanti in \secref{sec:file_fd}, quando tratteremo
+% Ritorneremo su questo più avanti in sez.~\ref{sec:file_fd}, quando tratteremo
% l'input/output sui file, esaminando in dettaglio come tutto ciò viene
% realizzato.
%% occorre una breve introduzione al funzionamento della gestione dei file da
%% parte del kernel e sugli oggetti su cui è basato un filesystem. In particolare
%% occorre tenere presente dov'è che si situa la divisione fondamentale fra
-%% kernel space e user space che tracciavamo al \capref{cha:intro_unix}.
+%% kernel space e user space che tracciavamo al cap.~\ref{cha:intro_unix}.
In questa sezione esamineremo come viene implementato l'accesso ai file in
Linux, come il kernel può gestire diversi tipi di filesystem, descrivendo
% in particolare si riprenderà, approfondendolo sul piano dell'uso nelle
% funzioni di libreria, il concetto di \textit{inode} di cui abbiamo brevemente
% accennato le caratteristiche (dal lato dell'implementazione nel kernel) in
-% \secref{sec:file_vfs}.
+% sez.~\ref{sec:file_vfs}.
\subsection{Il \textit{Virtual File System} di Linux}
opportune routine del filesystem specifico a cui si fa riferimento. Saranno
queste a chiamare le funzioni di più basso livello che eseguono le operazioni
di I/O sul dispositivo fisico, secondo lo schema riportato in
-\figref{fig:file_VFS_scheme}.
+fig.~\ref{fig:file_VFS_scheme}.
\begin{figure}[htb]
\centering
(o qualunque altro \textit{block device} che può contenere un filesystem), il
VFS può ricavare dalla citata tabella il puntatore alle funzioni da chiamare
nelle operazioni di montaggio. Quest'ultima è responsabile di leggere da disco
-il superblock (vedi \secref{sec:file_ext2}), inizializzare tutte le variabili
+il superblock (vedi sez.~\ref{sec:file_ext2}), inizializzare tutte le variabili
interne e restituire uno speciale descrittore dei filesystem montati al VFS;
attraverso quest'ultimo diventa possibile accedere alle routine specifiche per
l'uso di quel filesystem.
una directory, un link simbolico, una FIFO, un file di
dispositivo\index{file!di dispositivo}, o una qualsiasi altra cosa che possa
essere rappresentata dal VFS (i tipi di file riportati in
-\tabref{tab:file_file_types}). A ciascuno di essi è associata pure una
+tab.~\ref{tab:file_file_types}). A ciascuno di essi è associata pure una
struttura che sta in memoria, e che, oltre alle informazioni sullo specifico
file, contiene anche il riferimento alle funzioni (i \textsl{metodi} del VFS)
da usare per poterlo manipolare.
metodi che implementano le operazioni disponibili sul file. In questo modo i
processi in user space possono accedere alle operazioni attraverso detti
metodi, che saranno diversi a seconda del tipo di file (o dispositivo) aperto
-(su questo torneremo in dettaglio in \secref{sec:file_fd}). Un elenco delle
+(su questo torneremo in dettaglio in sez.~\ref{sec:file_fd}). Un elenco delle
operazioni previste dal kernel è riportato in
-\tabref{tab:file_file_operations}.
+tab.~\ref{tab:file_file_operations}.
\begin{table}[htb]
\centering
\textbf{Funzione} & \textbf{Operazione} \\
\hline
\hline
- \textsl{\code{open}} & apre il file (vedi \secref{sec:file_open}). \\
- \textsl{\code{read}} & legge dal file (vedi \secref{sec:file_read}).\\
- \textsl{\code{write}} & scrive sul file (vedi \secref{sec:file_write}).\\
+ \textsl{\code{open}} & apre il file (vedi sez.~\ref{sec:file_open}). \\
+ \textsl{\code{read}} & legge dal file (vedi sez.~\ref{sec:file_read}).\\
+ \textsl{\code{write}} & scrive sul file (vedi
+ sez.~\ref{sec:file_write}).\\
\textsl{\code{llseek}} & sposta la posizione corrente sul file (vedi
- \secref{sec:file_lseek}). \\
+ sez.~\ref{sec:file_lseek}). \\
\textsl{\code{ioctl}} & accede alle operazioni di controllo
- (vedi \secref{sec:file_ioctl}).\\
+ (vedi sez.~\ref{sec:file_ioctl}).\\
\textsl{\code{readdir}}& legge il contenuto di una directory \\
\textsl{\code{poll}} & usata nell'I/O multiplexing (vedi
- \secref{sec:file_multiplexing}). \\
+ sez.~\ref{sec:file_multiplexing}). \\
\textsl{\code{mmap}} & mappa il file in memoria (vedi
- \secref{sec:file_memory_map}). \\
+ sez.~\ref{sec:file_memory_map}). \\
\textsl{\code{release}}& chiamata quando l'ultimo riferimento a un file
aperto è chiuso. \\
\textsl{\code{fsync}} & sincronizza il contenuto del file (vedi
- \secref{sec:file_sync}). \\
+ sez.~\ref{sec:file_sync}). \\
\textsl{\code{fasync}} & abilita l'I/O asincrono (vedi
- \secref{sec:file_asyncronous_io}) sul file. \\
+ sez.~\ref{sec:file_asyncronous_io}) sul file. \\
\hline
\end{tabular}
\caption{Operazioni sui file definite nel VFS.}
\subsection{Il funzionamento di un filesystem Unix}
\label{sec:file_filesystem}
-Come già accennato in \secref{sec:file_organization} Linux (ed ogni sistema
+Come già accennato in sez.~\ref{sec:file_organization} Linux (ed ogni sistema
unix-like) organizza i dati che tiene su disco attraverso l'uso di un
filesystem. Una delle caratteristiche di Linux rispetto agli altri Unix è
quella di poter supportare, grazie al VFS, una enorme quantità di filesystem
Lo spazio fisico di un disco viene usualmente diviso in partizioni; ogni
partizione può contenere un filesystem. La strutturazione tipica
-dell'informazione su un disco è riportata in \figref{fig:file_disk_filesys};
+dell'informazione su un disco è riportata in fig.~\ref{fig:file_disk_filesys};
in essa si fa riferimento alla struttura del filesystem \acr{ext2}, che
prevede una separazione dei dati in \textit{blocks group} che replicano il
superblock (ma sulle caratteristiche di \acr{ext2} torneremo in
-\secref{sec:file_ext2}). È comunque caratteristica comune di tutti i
+sez.~\ref{sec:file_ext2}). È comunque caratteristica comune di tutti i
filesystem per Unix, indipendentemente da come poi viene strutturata nei
dettagli questa informazione, prevedere una divisione fra la lista degli
inode\index{inode} e lo spazio a disposizione per i dati e le directory.
relativi al funzionamento del filesystem stesso come la strutturazione in
gruppi dei blocchi, il superblock e tutti i dati di gestione) possiamo
esemplificare la situazione con uno schema come quello esposto in
-\figref{fig:file_filesys_detail}.
+fig.~\ref{fig:file_filesys_detail}.
\begin{figure}[htb]
\centering
\label{fig:file_filesys_detail}
\end{figure}
-Da \figref{fig:file_filesys_detail} si evidenziano alcune delle
+Da fig.~\ref{fig:file_filesys_detail} si evidenziano alcune delle
caratteristiche di base di un filesystem, sulle quali è bene porre attenzione
visto che sono fondamentali per capire il funzionamento delle funzioni che
manipolano i file e le directory che tratteremo nel prossimo capitolo; in
dell'\textit{inode}\index{inode} ad esso associato, cioè quella che da qui
in poi chiameremo una \textsl{voce} (come traduzione dell'inglese
\textit{directory entry}, che non useremo anche per evitare confusione con
- le \textit{dentry} del kernel di cui si parlava in \secref{sec:file_vfs}).
+ le \textit{dentry} del kernel di cui si parlava in sez.~\ref{sec:file_vfs}).
-\item Come mostrato in \figref{fig:file_filesys_detail} si possono avere più
+\item Come mostrato in fig.~\ref{fig:file_filesys_detail} si possono avere più
voci che puntano allo stesso \textit{inode}. Ogni \textit{inode} ha un
contatore che contiene il numero di riferimenti (\textit{link count}) che
sono stati fatti ad esso; solo quando questo contatore si annulla i dati del
Infine è bene avere presente che, essendo file pure loro, esiste un numero di
riferimenti anche per le directory; per cui, se a partire dalla situazione
-mostrata in \figref{fig:file_filesys_detail} creiamo una nuova directory
+mostrata in fig.~\ref{fig:file_filesys_detail} creiamo una nuova directory
\file{img} nella directory \file{gapil}, avremo una situazione come quella in
-\figref{fig:file_dirs_link}, dove per chiarezza abbiamo aggiunto dei numeri di
-inode\index{inode}.
+fig.~\ref{fig:file_dirs_link}, dove per chiarezza abbiamo aggiunto dei numeri
+di inode\index{inode}.
\begin{figure}[htb]
\centering
semantica SVr4 comporta che i file vengono creati con l'identificatore del
gruppo primario del processo, eccetto il caso in cui la directory ha il bit
di \acr{sgid} impostato (per una descrizione dettagliata del significato di
- questi termini si veda \secref{sec:file_access_control}), nel qual caso file
- e subdirectory ereditano sia il \acr{gid} che lo \acr{sgid}.
+ questi termini si veda sez.~\ref{sec:file_access_control}), nel qual caso
+ file e subdirectory ereditano sia il \acr{gid} che lo \acr{sgid}.
\item l'amministratore può scegliere la dimensione dei blocchi del filesystem
in fase di creazione, a seconda delle sue esigenze (blocchi più grandi
permettono un accesso più veloce, ma sprecano più spazio disco).
log).
\end{itemize}
-La struttura di \acr{ext2} è stata ispirata a quella del filesystem di BSD:
-un filesystem è composto da un insieme di blocchi, la struttura generale è
-quella riportata in \figref{fig:file_filesys_detail}, in cui la partizione
-è divisa in gruppi di blocchi.
+La struttura di \acr{ext2} è stata ispirata a quella del filesystem di BSD: un
+filesystem è composto da un insieme di blocchi, la struttura generale è quella
+riportata in fig.~\ref{fig:file_filesys_detail}, in cui la partizione è divisa
+in gruppi di blocchi.\footnote{non si confonda la questa definizione con
+ quella riportata in fig.~\ref{fig:file_dirent_struct}; in quel caso si fa
+ riferimento alla struttura usata in user space per riportare i dati
+ contenuti in una directory generica, questa fa riferimento alla struttura
+ usata dal kernel per un filesystem \acr{ext2}, definita nel file
+ \texttt{ext2\_fs.h} nella directory \texttt{include/linux} dei sorgenti del
+ kernel.}
Ciascun gruppo di blocchi contiene una copia delle informazioni essenziali del
filesystem (superblock e descrittore del filesystem sono quindi ridondati) per
Le directory sono implementate come una linked list con voci di dimensione
variabile. Ciascuna voce della lista contiene il numero di inode\index{inode},
la sua lunghezza, il nome del file e la sua lunghezza, secondo lo schema in
-\figref{fig:file_ext2_dirs}; in questo modo è possibile implementare nomi per
-i file anche molto lunghi (fino a 1024 caratteri) senza sprecare spazio disco.
+fig.~\ref{fig:file_ext2_dirs}; in questo modo è possibile implementare nomi
+per i file anche molto lunghi (fino a 1024 caratteri) senza sprecare spazio
+disco.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15.6cm}
- \includecodesample{listati/UDP_echo.c}
+ \includecodesample{listati/UDP_echo_first.c}
\end{minipage}
\normalsize
- \caption{Sezione principale del client per il servizio \textit{echo} su
- UDP.}
+ \caption{Sezione principale della prima versione client per il servizio
+ \textit{echo} su UDP.}
\label{fig:UDP_echo_client}
\end{figure}
\normalsize
\caption{Codice della funzione \func{ClientEcho} usata dal client per il
servizio \textit{echo} su UDP.}
- \label{fig:UDP_echo_clientecho}
+ \label{fig:UDP_echo_client_echo}
\end{figure}
Ovviamente in questo caso il funzionamento della funzione, il cui codice è
-riportato in fig.~\ref{fig:UDP_echo_clientecho}, è completamente diverso
+riportato in fig.~\ref{fig:UDP_echo_client_echo}, è completamente diverso
rispetto alla analoga del server TCP, e dato che non esiste una connessione
questa necessita anche di un terzo argomento, che è l'indirizzo del server cui
inviare i pacchetti.
Ci si può chiedere allora perché, benché la situazione di errore sia
rilevabile, questa non venga segnalata. Il luogo più naturale in cui
riportarla sarebbe la chiamata di \func{sendto}, in quanto è a causa dell'uso
-di indirizzo sbagliato che il pacchetto non può essere inviato; farlo in
+di un indirizzo sbagliato che il pacchetto non può essere inviato; farlo in
questo punto però è impossibile, dato che l'interfaccia di programmazione
-richiede che la funzione ritorni non appena il kernel invia il pacchetto, e
-non può bloccarsi in una attesa di una risposta che potrebbe essere molto
-lunga (si noti infatti che il pacchetto ICMP arriva qualche decimo di secondo
-più tardi) o non esserci affatto.
+richiede che la funzione ritorni non appena il kernel invia il
+pacchetto,\footnote{questo è il classico caso di \textsl{errore asincrono},
+ una situazione cioè in cui la condizione di errore viene rilevata in maniera
+ asincrona rispetto all'operazione che l'ha causata, una eventualità
+ piuttosto comune quando si ha a che fare con la rete, tutti i pacchetti ICMP
+ che segnalano errori rientrano in questa tipologia.} e non può bloccarsi in
+una attesa di una risposta che potrebbe essere molto lunga (si noti infatti
+che il pacchetto ICMP arriva qualche decimo di secondo più tardi) o non
+esserci affatto.
Si potrebbe allora pensare di riportare l'errore nella \func{recvfrom} che è
-comunque bloccata in attesa di una risposta che nel caso non non arriverà mai.
-La ragione di tutto questo è piuttosto sottile e viene trattata da Stevens in
-\cite{UNP2} con il seguente esempio: si consideri un client che invia tre
-pacchetti a tre diverse macchine, due quali vengono regolarmente ricevuti,
-mentre al terzo, non essendo presente un server sulla relativa macchina, viene
-risposto con un messaggio ICMP come il precedente. Detto messaggio conterrà
-anche le informazioni relative ad indirizzo e porta del pacchetto che ha
-fallito, però tutto quello che il kernel può restituire al programma è un
-codice di errore in \var{errno}, e pertanto è stata fatta la scelta di non
-riportare l'errore, a meno che, come vedremo in sez.~\ref{sec:UDP_connect}, il
-socket non sia connesso.
+comunque bloccata in attesa di una risposta che nel caso non arriverà mai. La
+ragione per cui non viene fatto è piuttosto sottile e viene spiegata da
+Stevens in \cite{UNP2} con il seguente esempio: si consideri un client che
+invia tre pacchetti a tre diverse macchine, due dei quali vengono regolarmente
+ricevuti, mentre al terzo, non essendo presente un server sulla relativa
+macchina, viene risposto con un messaggio ICMP come il precedente. Detto
+messaggio conterrà anche le informazioni relative ad indirizzo e porta del
+pacchetto che ha fallito, però tutto quello che il kernel può restituire al
+programma è un codice di errore in \var{errno}, con il quale è impossibile di
+distinguere per quale dei pacchetti inviati si è avuto l'errore; per questo è
+stata fatta la scelta di non riportare un errore su un socket UDP, a meno che,
+come vedremo in sez.~\ref{sec:UDP_connect}, questo non sia connesso.
Come illustrato in sez.~\ref{sec:UDP_characteristics} essendo i socket UDP
privi di connessione non è necessario per i client usare \func{connect} prima
-di iniziare una comunicazione con un server.
+di iniziare una comunicazione con un server. Ciò non di meno abbiamo accennato
+come questa possa essere utilizzata per gestire la presenza di errori
+asincroni.
+
+Quando si chiama \func{connect} su di un socket UDP tutto quello che succede è
+che l'indirizzo passato alla funzione viene registrato come indirizzo di
+destinazione del socket, a differenza di quanto avviene con TCP non viene
+scambiato nessun pacchetto; tutto quello che succede è che da quel momento in
+qualunque cosa si scriva sul socket sarà inviata a quell'indirizzo; non sarà
+più necessario usare l'argomento \param{to} di \func{sendto} per specificare
+la destinazione dei pacchetti, che potranno essere inviati e ricevuti usando
+le normali funzioni \func{read} e \func{write}.\footnote{in realtà si può
+ anche continuare ad usare la funzione \func{sendto}, ma in tal caso
+ l'argomento \param{to} deve essere inizializzato a \const{NULL}, e
+ \param{tolen} deve essere inizializzato a zero, pena un errore.}
+
+Una volta che il socket è connesso però cambia anche il comportamento in
+ricezione; prima infatti il kernel avrebbe restituito al socket qualunque
+pacchetto ricevuto con un indirizzo di destinazione corrispondente a quello
+del socket, senza nessun controllo sulla sorgente; una volta che il socket
+viene connesso saranno riportati su di esso solo i pacchetti con un indirizzo
+sorgente corrispondente a quello a cui ci si è connessi.
+
+Infine quando si è connesso un socket, venendo meno l'ambiguità segnalata alla
+fine di sez.~\ref{sec:UDP_problems}, tutti gli eventuali errori asincroni
+vengono riportati alle funzioni che operano su di esse, pertanto con le
+modifiche illustrate in fig.~\ref{fig:UDP_echo_conn_cli}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15.6cm}
+ \includecodesample{listati/UDP_echo.c}
+ \end{minipage}
+ \normalsize
+ \caption{Nuova sezione della seconda versione del client del servizio
+ \textit{echo} che utilizza socket UDP connessi.}
+ \label{fig:UDP_echo_conn_cli}
+\end{figure}
+
--- /dev/null
+/* UDP_echo_first.c
+ *
+ * Copyright (C) 2004 Simone Piccardi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/****************************************************************
+ *
+ * Program UDP_echo_first.c
+ * Simple UDP client for echo service (port 7)
+ * first version, no connected UDP socket
+ *
+ * Author: Simone Piccardi
+ * May 2004
+ *
+ * Usage: echo -h give all info's
+ *
+ * $Id: UDP_echo_first.c,v 1.1 2004/06/02 16:31:50 piccardi Exp $
+ *
+ ****************************************************************/
+/*
+ * Include needed headers
+ */
+#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 <errno.h> /* include error codes */
+#include <string.h> /* include erroro strings definitions */
+
+#include "macros.h"
+
+#define MAXLINE 256
+void usage(void);
+void ClientEcho(FILE * filein, int socket, struct sockaddr_in *serv_add);
+void SigTERM_hand(int sig);
+
+/* Program begin */
+int main(int argc, char *argv[])
+{
+/*
+ * Variables definition
+ */
+ int sock, i;
+ struct sockaddr_in serv_add;
+ /*
+ * Input section: decode parameters passed in the calling
+ * Use getopt function
+ */
+ opterr = 0; /* don't want writing to stderr */
+ while ( (i = getopt(argc, argv, "h")) != -1) {
+ switch (i) {
+ /*
+ * Handling options
+ */
+ case 'h':
+ printf("Wrong -h option use\n");
+ usage();
+ return(1);
+ break;
+ case '?': /* unrecognized options */
+ printf("Unrecognized options -%c\n",optopt);
+ usage();
+ default: /* should not reached */
+ usage();
+ }
+ }
+ /* ***********************************************************
+ *
+ * Options processing completed
+ *
+ * Main code beginning
+ *
+ * ***********************************************************/
+ /* create socket */
+ if ( (sock = socket(AF_INET, SOCK_DGRAM, 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(7); /* echo port is 7 */
+ /* build address using inet_pton */
+ if ( (inet_pton(AF_INET, argv[optind], &serv_add.sin_addr)) <= 0) {
+ perror("Address creation error");
+ return 1;
+ }
+ /* do read/write operations */
+ ClientEcho(stdin, sock, &serv_add);
+ /* normal exit */
+ return 0;
+}
+/*
+ * routine to print usage info and exit
+ */
+void usage(void) {
+ printf("Take daytime from a remote host \n");
+ printf("Usage:\n");
+ printf(" daytime [-h] [-v] [host in dotted decimal form] \n");
+// printf(" -v set verbosity on\n");
+ printf(" -r require reset on closing\n");
+ printf(" -h print this help\n");
+ exit(1);
+}
+
+void ClientEcho(FILE * filein, int socket, struct sockaddr_in * serv_addr)
+{
+ char sendbuff[MAXLINE+1], recvbuff[MAXLINE+1];
+ int nread, nwrite;
+ /* initialize file descriptor set */
+ while (1) {
+ if (fgets(sendbuff, MAXLINE, filein) == NULL) {
+ return; /* if no input just return */
+ } else { /* else we have to write to socket */
+ nwrite = sendto(socket, sendbuff, strlen(sendbuff), 0,
+ (struct sockaddr *) serv_addr, sizeof(*serv_addr));
+ if (nwrite < 0) { /* on error stop */
+ printf("Errore in scrittura: %s", strerror(errno));
+ return;
+ }
+ }
+ nread = recvfrom(socket, recvbuff, strlen(sendbuff), 0, NULL, NULL);
+ if (nread < 0) { /* error condition, stop client */
+ printf("Errore in lettura: %s\n", strerror(errno));
+ return;
+ }
+ recvbuff[nread] = 0; /* else read is ok, write on stdout */
+ if (fputs(recvbuff, stdout) == EOF) {
+ perror("Errore in scrittura su terminale");
+ return;
+ }
+ }
+}