From: Simone Piccardi Date: Wed, 2 Jun 2004 16:31:50 +0000 (+0000) Subject: Inserita una nota esplicativa sulla struttura dirent, su segnalazione di X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=2a09a578f80e369673bd5ac24179c021e903358b;p=gapil.git Inserita una nota esplicativa sulla struttura dirent, su segnalazione di Daniele Masini, Aggiunte note di TODO in prochand relativamente alla capabilities, iniziata la sezione sui socket UDP connessi, con quattro chiacchiere e la nuova versione del client --- diff --git a/ChangeLog b/ChangeLog index b27b03e..6e6c9e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2004-06-02 Simone Piccardi + + * fileintro.tex: aggiunta nota di chiarimento sulla struttura + dirent per evitare un fraintendimento segnalato da Daniele Masini. + 2004-04-25 Simone Piccardi * process.tex: correzioni da Paolo Giarrusso, refuso su BSS e tipo diff --git a/fileintro.tex b/fileintro.tex index 92efd2a..7d58c31 100644 --- a/fileintro.tex +++ b/fileintro.tex @@ -40,10 +40,10 @@ programmi le opportune interfacce che consentano di leggerne il contenuto; il 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 @@ -81,7 +81,7 @@ alcune strutture interne del kernel) sono generati automaticamente dal kernel 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 @@ -107,16 +107,16 @@ precedente usando \file{/} come separatore\footnote{nel caso di nome vuoto, il 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 @@ -132,18 +132,18 @@ se stessa. 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 @@ -168,7 +168,7 @@ in cui il dispositivo sottostante effettua le operazioni di I/O.\footnote{in 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} & @@ -177,10 +177,10 @@ in cui il dispositivo sottostante effettua le operazioni di I/O.\footnote{in 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} @@ -236,10 +236,10 @@ programmazione sono due, basate su due diversi meccanismi con cui 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 @@ -252,7 +252,8 @@ L'interfaccia 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 @@ -264,12 +265,12 @@ utilizzando il tipo \ctyp{FILE *}. L'interfaccia 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 @@ -333,12 +334,12 @@ portabilit % 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. @@ -351,7 +352,7 @@ portabilit %% 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 @@ -362,7 +363,7 @@ Linux, l'\acr{ext2}. % 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} @@ -390,7 +391,7 @@ manipolazioni sulle strutture generiche e utilizzer 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 @@ -416,7 +417,7 @@ In questo modo quando viene effettuata la richiesta di montare un nuovo disco (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. @@ -454,7 +455,7 @@ disco e che identifica un singolo oggetto del VFS sia esso un file ordinario, 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. @@ -489,9 +490,9 @@ una struttura di tipo \struct{file} in cui viene inserito un puntatore alla 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 @@ -501,24 +502,25 @@ operazioni previste dal kernel \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.} @@ -541,7 +543,7 @@ immediato e (relativamente) trasparente per l'utente ed il programmatore. \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 @@ -552,11 +554,11 @@ alle caratteristiche comuni di qualunque filesystem di sistema unix-like. 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. @@ -574,7 +576,7 @@ dell'informazione all'interno del singolo filesystem (tralasciando i dettagli 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 @@ -583,7 +585,7 @@ esemplificare la situazione con uno schema come quello esposto in \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 @@ -599,9 +601,9 @@ particolare 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 @@ -627,10 +629,10 @@ particolare 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 @@ -670,8 +672,8 @@ non sono presenti sugli altri filesystem Unix. Le principali sono le seguenti: 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). @@ -686,10 +688,16 @@ non sono presenti sugli altri filesystem Unix. Le principali sono le seguenti: 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 @@ -710,8 +718,9 @@ inode\index{inode}. 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. diff --git a/listati/UDP_echo.c b/listati/UDP_echo.c index 943ec75..f28a408 100644 --- a/listati/UDP_echo.c +++ b/listati/UDP_echo.c @@ -24,8 +24,9 @@ int main(int argc, char *argv[]) perror("Address creation error"); return 1; } + connect(sock, &serv_add, sizeof(*serv_add)); /* do read/write operations */ - ClientEcho(stdin, sock, &serv_add); + ClientEcho(stdin, sock); /* normal exit */ return 0; } diff --git a/listati/UDP_echo_first.c b/listati/UDP_echo_first.c new file mode 100644 index 0000000..943ec75 --- /dev/null +++ b/listati/UDP_echo_first.c @@ -0,0 +1,31 @@ +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; + ... + /* 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; +} diff --git a/othersock.tex b/othersock.tex index 7897c6e..d73aa57 100644 --- a/othersock.tex +++ b/othersock.tex @@ -498,11 +498,11 @@ possono avere proviamo allora con un servizio leggermente pi \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} @@ -524,11 +524,11 @@ per \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. @@ -617,25 +617,31 @@ irraggiungibile che ci segnala che la porta in questione non risponde. 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. @@ -644,7 +650,45 @@ socket 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} + diff --git a/prochand.tex b/prochand.tex index f8e2fee..86c7a7d 100644 --- a/prochand.tex +++ b/prochand.tex @@ -1843,6 +1843,19 @@ compila con il flag \cmd{-ansi}, scrivere codice portabile. +% +% Da fare !!! +% insieme alla risistemazioni dei titoli delle sezioni precedenti +% (accorpare il materiale) qualosa tipo: +% le funzioni di controllo +% estenzioni di Linux +% +%\subsection{La gestione delle capabilities} +%\label{sec:proc_capabilities} + + + + \section{La gestione della priorità di esecuzione} \label{sec:proc_priority} diff --git a/sources/UDP_echo.c b/sources/UDP_echo.c index b14e1f6..a3bbd9b 100644 --- a/sources/UDP_echo.c +++ b/sources/UDP_echo.c @@ -26,7 +26,7 @@ * * Usage: echo -h give all info's * - * $Id: UDP_echo.c,v 1.2 2004/05/02 13:10:32 piccardi Exp $ + * $Id: UDP_echo.c,v 1.3 2004/06/02 16:31:50 piccardi Exp $ * ****************************************************************/ /* @@ -98,8 +98,9 @@ int main(int argc, char *argv[]) perror("Address creation error"); return 1; } + connect(sock, &serv_add, sizeof(*serv_add)); /* do read/write operations */ - ClientEcho(stdin, sock, &serv_add); + ClientEcho(stdin, sock); /* normal exit */ return 0; } @@ -116,7 +117,7 @@ void usage(void) { exit(1); } -void ClientEcho(FILE * filein, int socket, struct sockaddr_in * serv_addr) +void ClientEcho(FILE * filein, int socket) { char sendbuff[MAXLINE+1], recvbuff[MAXLINE+1]; int nread, nwrite; @@ -125,14 +126,13 @@ void ClientEcho(FILE * filein, int socket, struct sockaddr_in * serv_addr) 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)); + nwrite = write(socket, sendbuff, strlen(sendbuff)); if (nwrite < 0) { /* on error stop */ printf("Errore in scrittura: %s", strerror(errno)); return; } } - nread = recvfrom(socket, recvbuff, strlen(sendbuff), 0, NULL, NULL); + nread = read(socket, recvbuff, strlen(sendbuff)); if (nread < 0) { /* error condition, stop client */ printf("Errore in lettura: %s\n", strerror(errno)); return; diff --git a/sources/UDP_echo_first.c b/sources/UDP_echo_first.c new file mode 100644 index 0000000..b30c12c --- /dev/null +++ b/sources/UDP_echo_first.c @@ -0,0 +1,147 @@ +/* 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 /* predefined types */ +#include /* include unix standard library */ +#include /* IP addresses conversion utiliites */ +#include /* socket library */ +#include /* include standard I/O library */ +#include /* include error codes */ +#include /* 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; + } + } +}