From: Simone Piccardi Date: Sun, 27 Jul 2003 23:41:04 +0000 (+0000) Subject: Risistemato tutto il primo esempio di server echo e le funzioni FullWrite e X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=49ae2790472cc2ad1e54ea26d037306598f9c83b;p=gapil.git Risistemato tutto il primo esempio di server echo e le funzioni FullWrite e FullRead. --- diff --git a/elemtcp.tex b/elemtcp.tex index 1ae67f4..b366d5f 100644 --- a/elemtcp.tex +++ b/elemtcp.tex @@ -71,7 +71,7 @@ scambiati) che porta alla creazione di una connessione client, inoltre anche il server deve inviare il suo SYN al client (e trasmettere il suo numero di sequenza iniziale) questo viene fatto ritrasmettendo un singolo segmento in cui sono impostati entrambi i flag SYN - ACK. + e ACK. \item una volta che il client ha ricevuto l'acknowledge dal server la funzione \func{connect} ritorna, l'ultimo passo è dare dare il ricevuto del SYN del @@ -101,7 +101,7 @@ stabilisce la connessione. \end{figure} Si è accennato in precedenza ai \textsl{numeri di sequenza} (che sono anche -riportati in \figref{fig:TCP_TWH}); per gestire una connessione affidabile +riportati in \figref{fig:TCP_TWH}): per gestire una connessione affidabile infatti il protocollo TCP prevede nell'header la presenza di un numero a 32 bit (chiamato appunto \textit{sequence number}) che identifica a quale byte nella sequenza del flusso corrisponde il primo byte della sezione dati @@ -170,29 +170,27 @@ elevati. In ogni caso Linux supporta pienamente entrambe le opzioni. \subsection{La terminazione della connessione} \label{sec:TCP_conn_term} -Mentre per creare una connessione occorre un interscambio di tre segmenti, la -procedura di chiusura ne richiede quattro; ancora una volta si può fare -riferimento al codice degli esempi \figref{fig:TCP_daytime_client_code} e -\figref{fig:TCP_daytime_iter_server_code}, in questo caso la successione degli -eventi è la seguente: +Mentre per la creazione di una connessione occorre un interscambio di tre +segmenti, la procedura di chiusura ne richiede normalmente quattro. In questo +caso la successione degli eventi è la seguente: \begin{enumerate} \item Un processo ad uno dei due capi chiama la funzione \func{close}, dando l'avvio a quella che viene chiamata \textsl{chiusura attiva} (o \textit{active close}). Questo comporta l'emissione di un segmento FIN, che - significa che si è finito con l'invio dei dati sulla connessione. + serve ad indicare che si è finito con l'invio dei dati sulla connessione. -\item L'altro capo della connessione riceve il FIN ed esegue la - \textsl{chiusura passiva} (o \textit{passive close}); al FIN, come ad ogni - altro pacchetto, viene risposto con un ACK. Inoltre il ricevimento del FIN +\item L'altro capo della connessione riceve il FIN e dovrà eseguire la + \textsl{chiusura passiva} (o \textit{passive close}). Al FIN, come ad ogni + altro pacchetto, viene risposto con un ACK, inoltre il ricevimento del FIN viene segnalato al processo che ha aperto il socket (dopo che ogni altro eventuale dato rimasto in coda è stato ricevuto) come un end-of-file sulla - lettura, questo perché il ricevimento di un FIN significa che non si + lettura: questo perché il ricevimento di un FIN significa che non si riceveranno altri dati sulla connessione. - -\item Dopo un certo tempo anche il secondo processo chiamerà la funzione - \func{close} sul proprio socket, causando l'emissione di un altro segmento - FIN. + +\item Una volta rilevata l'end-of-file anche il secondo processo chiamerà la + funzione \func{close} sul proprio socket, causando l'emissione di un altro + segmento FIN. \item L'altro capo della connessione riceverà il FIN conclusivo e risponderà con un ACK. @@ -352,10 +350,8 @@ Ogni implementazione del TCP deve scegliere un valore per la MSL (l'\href{http://www.ietf.org/rfc/rfc1122.txt}{RFC~1122} raccomanda 2 minuti, Linux usa 30 secondi), questo comporta una durata dello stato \texttt{TIME\_WAIT} che a seconda delle implementazioni può variare fra 1 a 4 -minuti. - -Lo stato \texttt{TIME\_WAIT} viene utilizzato dal protocollo per due motivi -principali: +minuti. Lo stato \texttt{TIME\_WAIT} viene utilizzato dal protocollo per due +motivi principali: \begin{enumerate} \item implementare in maniera affidabile la terminazione della connessione in entrambe le direzioni. @@ -379,13 +375,13 @@ verrebbe interpretato come un errore. Se il TCP deve poter chiudere in maniera pulita entrambe le direzioni della connessione allora deve essere in grado di affrontare la perdita di uno qualunque dei quattro segmenti che costituiscono la chiusura. Per questo -motivo lo stato \texttt{TIME\_WAIT} deve essere mantenuto anche dopo l'invio -dell'ultimo ACK per poter essere in grado di poterne gestire l'eventuale -ritrasmissione in caso di perdita. +motivo un socket deve rimanere attivo nello stato \texttt{TIME\_WAIT} anche +dopo l'invio dell'ultimo ACK, per potere essere in grado di gestirne +l'eventuale ritrasmissione, in caso esso venga perduto. Il secondo motivo è più complesso da capire, e necessita di una spiegazione -degli scenari in cui accade che i pacchetti si possano perdere nella rete o -restare intrappolati, per poi riemergere in un secondo tempo. +degli scenari in cui può accadere che i pacchetti TCP si possano perdere nella +rete o restare intrappolati, per poi riemergere in un secondo tempo. Il caso più comune in cui questo avviene è quello di anomalie nell'instradamento; può accadere cioè che un router smetta di funzionare o che @@ -397,13 +393,13 @@ pacchetti verso un'altro e quest'ultimo li rispedisce indietro, o li manda ad un terzo router che li rispedisce al primo, si creano cioè dei circoli (i cosiddetti \textit{routing loop}) in cui restano intrappolati i pacchetti. -Se uno di questi pacchetti intrappolati è un segmento TCP chi l'ha inviato, +Se uno di questi pacchetti intrappolati è un segmento TCP, chi l'ha inviato, non ricevendo un ACK in risposta, provvederà alla ritrasmissione e se nel frattempo sarà stata stabilita una strada alternativa il pacchetto ritrasmesso giungerà a destinazione. Ma se dopo un po' di tempo (che non supera il limite dell'MSL, dato che -altrimenti verrebbe ecceduto il TTL) l'anomalia viene a cessare il circolo di +altrimenti verrebbe ecceduto il TTL) l'anomalia viene a cessare, il circolo di instradamento viene spezzato i pacchetti intrappolati potranno essere inviati alla destinazione finale, con la conseguenza di avere dei pacchetti duplicati; questo è un caso che il TCP deve essere in grado di gestire. @@ -411,7 +407,8 @@ questo Allora per capire la seconda ragione per l'esistenza dello stato \texttt{TIME\_WAIT} si consideri il caso seguente: si supponga di avere una connessione fra l'IP \texttt{195.110.112.236} porta 1550 e l'IP -\texttt{192.84.145.100} porta 22, che questa venga chiusa e che poco dopo si +\texttt{192.84.145.100} porta 22 (affronteremo il significato delle porte +nella prossima sezione), che questa venga chiusa e che poco dopo si ristabilisca la stessa connessione fra gli stessi IP sulle stesse porte (quella che viene detta, essendo gli stessi porte e numeri IP, una nuova \textsl{incarnazione} della connessione precedente); in questo caso ci si @@ -445,8 +442,8 @@ Quando un client contatta un server deve poter identificare con quale dei vari possibili server attivi intende parlare. Sia TCP che UDP definiscono un gruppo di \textsl{porte conosciute} (le cosiddette \textit{well-known port}) che identificano una serie di servizi noti (ad esempio la porta 22 identifica il -servizio \textit{ssh}) effettuati da appositi server che rispondono alle -connessioni verso tali porte. +servizio SSH) effettuati da appositi server che rispondono alle connessioni +verso tali porte. D'altra parte un client non ha necessità di usare un numero di porta specifico, per cui in genere vengono usate le cosiddette \textsl{porte @@ -460,7 +457,7 @@ La lista delle porte conosciute dall'\href{http://www.ietf.org/rfc/rfc1700.txt}{RFC~1700} che contiene l'elenco delle porte assegnate dalla IANA (la \textit{Internet Assigned Number Authority}) ma l'elenco viene costantemente aggiornato e pubblicato su -internet (una versione corrente si può trovare all'indirizzo +internet (una versione aggiornata si può trovare all'indirizzo \texttt{ftp://ftp.isi.edu/in-notes/iana/assignements/port-numbers}); inoltre in un sistema unix-like un analogo elenco viene mantenuto nel file \file{/etc/services}, con la corrispondenza fra i vari numeri di porta ed il @@ -470,7 +467,7 @@ nome simbolico del servizio. I numeri sono divisi in tre intervalli: \item \textsl{le porte conosciute}. I numeri da 0 a 1023. Queste sono controllate e assegnate dalla IANA. Se è possibile la stessa porta è assegnata allo stesso servizio sia su UDP che su TCP (ad esempio la porta 22 - è assegnata a ssh su entrambi i protocolli, anche se viene usata solo dal + è assegnata a SSH su entrambi i protocolli, anche se viene usata solo dal TCP). \item \textsl{le porte registrate}. I numeri da 1024 a 49151. Queste porte non @@ -503,15 +500,16 @@ tabelle. I sistemi Unix hanno inoltre il concetto di \textsl{porte riservate} (che corrispondono alle porte con numero minore di 1024 e coincidono quindi con le porte conosciute). La loro caratteristica è che possono essere assegnate a un -socket solo da un processo con i privilegi di amministratore, per far si che solo -l'amministratore possa allocare queste porte per far partire i relativi +socket solo da un processo con i privilegi di amministratore, per far si che +solo l'amministratore possa allocare queste porte per far partire i relativi servizi. -Si tenga conto poi che ci sono alcuni client (in particolare \cmd{rsh} e -\cmd{rlogin}) che richiedono una connessione su una porta riservata anche -dal lato client come parte dell'autenticazione. Questo viene fatto tramite la -funzione \func{rresvport} assegnando al socket una porta libera -nell'intervallo fra 512 e 1023. +Si tenga conto poi che ci sono alcuni client, in particolare \cmd{rsh} e +\cmd{rlogin}, che richiedono una connessione su una porta riservata anche dal +lato client come parte dell'autenticazione, contando appunto sul fatto che +solo l'amministratore può usare queste porte. Data l'assoluta inconsistenza in +termini di sicurezza di un tale metodo, al giorno d'oggi esso è in completo +disuso. Data una connessione TCP si suole chiamare \textit{socket pair}\footnote{da non confondere con la coppia di socket della omonima funzione @@ -532,7 +530,7 @@ queste informazioni nei campi \textit{Local Address} e \textit{Foreing \label{sec:TCP_port_cliserv} Per capire meglio l'uso delle porte e come vengono utilizzate quando si ha a -che fare con un'applicazione client/server (come quelle che scriveremo in +che fare con un'applicazione client/server (come quelle che descriveremo in \secref{sec:TCP_daytime_application} e \secref{sec:TCP_echo_application}) esamineremo cosa accade con le connessioni nel caso di un server TCP che deve gestire connessioni multiple. @@ -546,10 +544,10 @@ tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN \end{verbatim} -essendo presenti e attivi un server ssh, un server di posta e un DNS per il +essendo presenti e attivi un server SSH, un server di posta e un DNS per il caching locale. -Questo ci mostra ad esempio che il server ssh ha compiuto un'apertura passiva, +Questo ci mostra ad esempio che il server SSH ha compiuto un'apertura passiva, mettendosi in ascolto sulla porta 22 riservata a questo servizio, e che si è posto in ascolto per connessioni provenienti da uno qualunque degli indirizzi associati alle interfacce locali. La notazione \texttt{0.0.0.0} usata da @@ -625,13 +623,13 @@ dalla porta remota 21100 vanno al primo figlio e quelli che arrivano alla porta 21101 al secondo. -\section{Le funzioni dei socket TCP} +\section{Le funzioni di base per la gestione dei socket} \label{sec:TCP_functions} -In questa sezione descriveremo in dettaglio le varie funzioni necessarie per -l'uso dei socket TCP, con l'eccezione della funzione \func{socket} che è già -stata esaminata in dettaglio nel capitolo precedente in -\secref{sec:sock_socket}. +In questa sezione descriveremo in maggior dettaglio le varie funzioni che +vengono usate per la gestione di base dei socket TCP, non torneremo però sulla +funzione \func{socket}, che è già stata esaminata accuratamente nel capitolo +precedente in \secref{sec:sock_socket}. \subsection{La funzione \func{bind}} @@ -669,8 +667,8 @@ Il primo argomento l'indirizzo (locale) del socket e la dimensione della struttura che lo contiene, secondo quanto già trattato in \secref{sec:sock_sockaddr}. -Con il TCP la chiamata \func{bind} permette di specificare l'indirizzo, la -porta, entrambi o nessuno dei due. In genere i server utilizzano una porta +Con i socket TCP la chiamata \func{bind} permette di specificare l'indirizzo, +la porta, entrambi o nessuno dei due. In genere i server utilizzano una porta nota che assegnano all'avvio, se questo non viene fatto è il kernel a scegliere una porta effimera quando vengono eseguite la funzioni \func{connect} o \func{listen}, ma se questo è normale per il client non lo è @@ -690,7 +688,7 @@ alle connessioni che arrivano verso tale indirizzo. Normalmente un client non specifica mai l'indirizzo di un socket, ed il kernel sceglie l'indirizzo di origine quando viene effettuata la connessione, sulla -base dell'interfaccia usata per trasmettere i pacchetti, (che dipende dalle +base dell'interfaccia usata per trasmettere i pacchetti, (che dipenderà dalle regole di instradamento usate per raggiungere il server). Se un server non specifica il suo indirizzo locale il kernel userà come indirizzo di origine l'indirizzo di destinazione specificato dal SYN del client. @@ -755,7 +753,7 @@ connessione con un server TCP, il prototipo della funzione Stabilisce una connessione fra due socket. \bodydesc{La funzione restituisce zero in caso di successo e -1 per un - errore, in caso di errore \var{errno} assumerà i valori: + errore, nel qual caso \var{errno} assumerà i valori: \begin{errlist} \item[\errcode{ECONNREFUSED}] non c'è nessuno in ascolto sull'indirizzo remoto. @@ -1233,9 +1231,9 @@ socket di tipo stream). Infatti con i socket è comune che funzioni come \func{read} o \func{write} possano restituire in input o scrivere in output un numero di byte minore di quello richiesto. Come già accennato in \secref{sec:file_read} questo è un -comportamento normale per l'I/O su file, ma con i normali file di dati il -problema si avverte solo quando si incontra la fine del file. In generale non -è così, e con i socket questo è particolarmente evidente. +comportamento normale per le funzioni di I/O, ma con i normali file di dati il +problema si avverte solo in lettura, quando si incontra la fine del file. In +generale non è così, e con i socket questo è particolarmente evidente. \begin{figure}[htb] @@ -1286,15 +1284,18 @@ l'errore viene ritornato al programma chiamante, interrompendo il ciclo. Nel caso della lettura, se il numero di byte letti è zero, significa che si è arrivati alla fine del file (per i socket questo significa in genere che l'altro capo è stato chiuso, e quindi non sarà più possibile leggere niente) e -pertanto si ritorna senza aver concluso la lettura di tutti i byte richiesti. +pertanto si ritorna senza aver concluso la lettura di tutti i byte +richiesti. Entrambe le funzioni restituiscono 0 in caso di successo, ed un +valore negativo in caso di errore, \texttt{FullRead} restituisce il numero di +byte non letti in caso di end-of-file prematuro. \subsection{Il client \textit{daytime}} \label{sec:TCP_daytime_client} Il primo esempio di applicazione delle funzioni di base illustrate in -precedenza è relativo alla creazione di un client elementare per il servizio -\textit{daytime}, un servizio elementare, definito +\secref{sec:TCP_functions} è relativo alla creazione di un client elementare +per il servizio \textit{daytime}, un servizio elementare, definito nell'\href{http://www.ietf.org/rfc/rfc0867.txt}{RFC~867}, che restituisce l'ora locale della macchina a cui si effettua la richiesta, e che è assegnato alla porta 13. @@ -1526,7 +1527,7 @@ ulteriori connessioni. Si noti come il figlio operi solo sul socket connesso, chiudendo immediatamente (\texttt{\small 32}) il socket \var{list\_fd}; mentre il padre -continua ad operare solo sul socket in ascolto chiudendo (\texttt{\small 47}) +continua ad operare (\texttt{\small 47}) solo sul socket in ascolto chiudendo \var{sock\_fd} al ritorno dalla \func{fork}. Per quanto abbiamo detto in \secref{sec:TCP_func_close} nessuna delle due chiamate a \func{close} causa l'innesco della sequenza di chiusura perché il numero di riferimenti al file @@ -1680,9 +1681,14 @@ Si usa poi (\texttt{\small 6}) la funzione \func{FullWrite}, vista in \secref{sec:sock_io_behav}, per scrivere i dati sul socket, gestendo automaticamente l'invio multiplo qualora una singola \func{write} non sia sufficiente. I dati vengono riletti indietro (\texttt{\small 7}) con una -\func{FullRead} sul buffer di ricezione e viene inserita (\texttt{\small 8}) -la terminazione della stringa e per poter usare (\texttt{\small 9}) la -funzione \func{fputs} per scriverli su \file{stdout}. +\func{read}\footnote{si è fatta l'assunzione implicita che i dati siano + contenuti tutti in un solo segmento, così che la chiamata a \texttt{read} li + restituisca sempre tutti; avendo scelto una dimensione ridotta per il buffer + questo sarà sempre vero, vedremo più avanti come superare il problema di + rileggere indietro tutti e soli i dati disponibili, senza bloccarsi.} sul +buffer di ricezione e viene inserita (\texttt{\small 8}) la terminazione della +stringa e per poter usare (\texttt{\small 9}) la funzione \func{fputs} per +scriverli su \file{stdout}. \begin{figure}[!htb] \footnotesize \centering @@ -1793,13 +1799,13 @@ errore attraverso il sistema del \textit{syslog} trattato in \textit{wrapper} la funzione \code{PrintErr}, il cui codice è riportato in \figref{fig:TCP_PrintErr}. -In essa ci si limita a controllare se è stato impostato (valore attivo per -default) l'uso come demone, nel qual caso (\texttt{\small 3}) si usa -\func{syslog} per stampare il messaggio di errore fornito come argomento sui -log di sistema. Se invece si è in modalità interattiva (attivabile con -l'opzione \texttt{-i}) si usa semplicemente la funzione \func{perror} per -stampare sullo standard error. - +In essa ci si limita a controllare (\texttt{\small 2}) se è stato impostato +(valore attivo per default) l'uso come demone, nel qual caso (\texttt{\small + 3}) si usa \func{syslog} (vedi \secref{sec:sess_daemon}) per stampare il +messaggio di errore fornito come argomento sui log di sistema. Se invece si è +in modalità interattiva (attivabile con l'opzione \texttt{-i}) si usa +(\texttt{\small 5}) semplicemente la funzione \func{perror} per stampare sullo +standard error. \begin{figure}[!htb] \footnotesize \centering @@ -1815,18 +1821,20 @@ stampare sullo standard error. La gestione del servizio \textit{echo} viene effettuata interamente nella funzione \code{ServEcho}, il cui codice è mostrato in -\figref{fig:TCP_ServEcho}, la comunicazione viene gestita all'interno del -ciclo (\texttt{\small 6--8}). I dati inviati dal client vengono letti dal -socket con una semplice \func{read} (che ritorna solo in presenza di dati in -arrivo), la riscrittura viene invece gestita dalla funzione \func{FullWrite} -(descritta in \figref{fig:sock_FullWrite_code}) che si incarica di tenere -conto automaticamente della possibilità che non tutti i dati di cui è -richiesta la scrittura vengano trasmessi con una singola \func{write}. +\figref{fig:TCP_ServEcho}, e la comunicazione viene gestita all'interno di un +ciclo (\texttt{\small 6--13}). I dati inviati dal client vengono letti +(\texttt{\small 6}) dal socket con una semplice \func{read}, di cui non si +controlla lo stato di uscita, assumendo che ritorni solo in presenza di dati +in arrivo. La riscrittura (\texttt{\small 7}) viene invece gestita dalla +funzione \func{FullWrite} (descritta in \figref{fig:sock_FullWrite_code}) che +si incarica di tenere conto automaticamente della possibilità che non tutti i +dati di cui è richiesta la scrittura vengano trasmessi con una singola +\func{write}. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15.6cm} - \includecodesample{listati/ServEcho.c} + \includecodesample{listati/ServEcho_first.c} \end{minipage} \normalsize \caption{Codice della prima versione della funzione \code{ServEcho} per la @@ -1834,15 +1842,12 @@ richiesta la scrittura vengano trasmessi con una singola \func{write}. \label{fig:TCP_ServEcho} \end{figure} -Nella funzione si è anche inserita la possibilità (\texttt{\small 7--14}) di -inviare dei messaggi di debug (abilitabile con l'uso dell'opzione \texttt{-d} -che imposta opportunamente \var{debugging}), gestendo entrambi i casi in cui -la stampa deve essere effettuata tramite \func{syslog} (\texttt{\small 11}) o -direttamente sullo standard output (\texttt{\small 13}). - -Quando il client chiude la connessione il ricevimento del FIN fa ritornare la -\func{read} con un numero di byte letti pari a zero, il che causa l'uscita dal -ciclo e il ritorno della funzione, che a sua volta causa la terminazione del +In caso di errore di scrittura (si ricordi che \func{FullWrite} restituisce un +vamore nullo in caso di successo) si provvede (\texttt{\small 8--10}) a +stampare il relativo messaggio con \func{PrintErr}. Quando il client chiude +la connessione il ricevimento del FIN fa ritornare la \func{read} con un +numero di byte letti pari a zero, il che causa l'uscita dal ciclo e il ritorno +(\texttt{\small 12}) della funzione, che a sua volta causa la terminazione del processo figlio. @@ -1850,7 +1855,7 @@ processo figlio. \label{sec:TCP_echo_startup} Benché il codice dell'esempio precedente sia molto ridotto, esso ci permetterà -di considerare in dettaglio tutte le problematiche che si possono incontrare +di considerare in dettaglio le varie problematiche che si possono incontrare nello scrivere un'applicazione di rete. Infatti attraverso l'esame delle sue modalità di funzionamento normali, all'avvio e alla terminazione, e di quello che avviene nelle varie situazioni limite, da una parte potremo approfondire @@ -1952,8 +1957,8 @@ quando affronteremo il comportamento in caso di conclusioni anomale: \begin{enumerate} \item inviando un carattere di EOF da terminale la \func{fgets} ritorna - restituendo un puntatore nullo che causa l'uscita dal ciclo di - \code{while}, così la \code{ClientEcho} ritorna. + restituendo un puntatore nullo che causa l'uscita dal ciclo di \code{while}, + così la funzione \code{ClientEcho} ritorna. \item al ritorno di \code{ClientEcho} ritorna anche la funzione \code{main}, e come parte del processo terminazione tutti i file descriptor vengono chiusi (si ricordi quanto detto in \secref{sec:proc_term_conclusion}); questo causa @@ -2200,6 +2205,14 @@ della chiusura del socket. +Nella funzione si è anche inserita (\texttt{\small 16--24}) la possibilità di +inviare dei messaggi di debug (abilitabile con l'uso dell'opzione \texttt{-d} +che imposta opportunamente \var{debugging}), gestendo entrambi i casi in cui +la stampa deve essere effettuata tramite \func{syslog} (\texttt{\small 20}) o +direttamente sullo standard output (\texttt{\small 22}). + + + %%% Local Variables: %%% mode: latex %%% TeX-master: "gapil" diff --git a/listati/ClientEcho.c b/listati/ClientEcho.c index cff81bf..9a18289 100644 --- a/listati/ClientEcho.c +++ b/listati/ClientEcho.c @@ -4,7 +4,7 @@ void ClientEcho(FILE * filein, int socket) int nread; while (fgets(sendbuff, MAXLINE, filein) != NULL) { FullWrite(socket, sendbuff, strlen(sendbuff)); - nread = FullRead(socket, recvbuff, strlen(sendbuff)); + nread = read(socket, recvbuff, strlen(sendbuff)); recvbuff[nread] = 0; fputs(recvbuff, stdout); } diff --git a/listati/FullRead.c b/listati/FullRead.c index fcc265b..33185ca 100644 --- a/listati/FullRead.c +++ b/listati/FullRead.c @@ -19,5 +19,5 @@ ssize_t FullRead(int fd, void *buf, size_t count) nleft -= nread; /* set left to read */ buf +=nread; /* set pointer */ } - return (count - nleft); + return (nleft); } diff --git a/listati/FullWrite.c b/listati/FullWrite.c index 505a1b8..25f8649 100644 --- a/listati/FullWrite.c +++ b/listati/FullWrite.c @@ -17,5 +17,5 @@ ssize_t FullWrite(int fd, const void *buf, size_t count) nleft -= nwritten; /* set left to write */ buf +=nwritten; /* set pointer */ } - return (count); + return (nleft); } diff --git a/listati/PrintErr.c b/listati/PrintErr.c index e6577d4..6a9a2db 100644 --- a/listati/PrintErr.c +++ b/listati/PrintErr.c @@ -1,6 +1,6 @@ void PrintErr(char * error) { - if (demonize) { - syslog(LOG_ERR, error); + if (demonize) { /* daemon mode */ + syslog(LOG_ERR, "%s: %m", error); /* log string and error message */ } else { perror(error); } diff --git a/listati/ServEcho_first.c b/listati/ServEcho_first.c new file mode 100644 index 0000000..1cda55c --- /dev/null +++ b/listati/ServEcho_first.c @@ -0,0 +1,13 @@ +void ServEcho(int sockfd) { + char buffer[MAXLINE]; + int nread, nwrite; + char debug[MAXLINE+20]; + /* main loop, reading 0 char means client close connection */ + while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) { + nwrite = FullWrite(sockfd, buffer, nread); + if (nwrite) { + PrintErr("write error"); + } + } + return; +} diff --git a/socket.tex b/socket.tex index 06ef46a..0d35c3e 100644 --- a/socket.tex +++ b/socket.tex @@ -13,8 +13,8 @@ In questo capitolo inizieremo a spiegare le caratteristiche salienti della principale interfaccia per la programmazione di rete, quella dei -\textit{socket}, che, pur essendo nata in ambiente Unix è usata ormai da tutti -i sistemi operativi. +\textit{socket}, che, pur essendo nata in ambiente Unix, è usata ormai da +tutti i sistemi operativi. Dopo una breve panoramica sulle caratteristiche di questa interfaccia vedremo come creare un socket e come collegarlo allo specifico protocollo di rete che diff --git a/sources/FullRead.c b/sources/FullRead.c index dab56a3..6338c52 100644 --- a/sources/FullRead.c +++ b/sources/FullRead.c @@ -24,7 +24,7 @@ * Author: Simone Piccardi * Jun. 2001 * - * $Id: FullRead.c,v 1.3 2003/05/02 09:55:13 piccardi Exp $ + * $Id: FullRead.c,v 1.4 2003/07/27 23:41:04 piccardi Exp $ * ****************************************************************/ #include @@ -49,6 +49,6 @@ ssize_t FullRead(int fd, void *buf, size_t count) nleft -= nread; /* set left to read */ buf +=nread; /* set pointer */ } - return (count - nleft); + return (nleft); } diff --git a/sources/FullWrite.c b/sources/FullWrite.c index 5c27bed..f90e91a 100644 --- a/sources/FullWrite.c +++ b/sources/FullWrite.c @@ -24,7 +24,7 @@ * Author: Simone Piccardi * Jun. 2001 * - * $Id: FullWrite.c,v 1.3 2003/05/02 09:55:13 piccardi Exp $ + * $Id: FullWrite.c,v 1.4 2003/07/27 23:41:04 piccardi Exp $ * ****************************************************************/ #include @@ -47,6 +47,6 @@ ssize_t FullWrite(int fd, const void *buf, size_t count) nleft -= nwritten; /* set left to write */ buf +=nwritten; /* set pointer */ } - return (count); + return (nleft); } diff --git a/sources/TCP_echo.c b/sources/TCP_echo.c index 8492986..275d570 100644 --- a/sources/TCP_echo.c +++ b/sources/TCP_echo.c @@ -26,7 +26,7 @@ * * Usage: echo -h give all info's * - * $Id: TCP_echo.c,v 1.4 2003/07/27 15:20:45 piccardi Exp $ + * $Id: TCP_echo.c,v 1.5 2003/07/27 23:41:04 piccardi Exp $ * ****************************************************************/ /* @@ -144,7 +144,7 @@ void ClientEcho(FILE * filein, int socket) if (nwrite < 0) { printf("Errore in scrittura %s", strerror(errno)); } - nread = read(socket, recvbuff, strlen(sendbuff)); + nread = FullRead(socket, recvbuff, strlen(sendbuff)); if (nread < 0) { printf("Errore in lettura %s", strerror(errno)); } diff --git a/sources/TCP_echo_first.c b/sources/TCP_echo_first.c index 626d196..93083b3 100644 --- a/sources/TCP_echo_first.c +++ b/sources/TCP_echo_first.c @@ -1,6 +1,6 @@ -/* TCP_echo1.c +/* TCP_echo_first.c * - * Copyright (C) 2001 Simone Piccardi + * Copyright (C) 2001-2003 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 @@ -18,7 +18,7 @@ */ /**************************************************************** * - * Program ElemEchoTCPClient.c + * Program TCP_echo_first.c (former ElemEchoTCPClient) * Simple TCP client for echo service (port 7) * * Author: Simone Piccardi @@ -26,7 +26,7 @@ * * Usage: echo -h give all info's * - * $Id: TCP_echo_first.c,v 1.1 2003/06/19 12:08:11 piccardi Exp $ + * $Id: TCP_echo_first.c,v 1.2 2003/07/27 23:41:04 piccardi Exp $ * ****************************************************************/ /* @@ -121,7 +121,7 @@ void ClientEcho(FILE * filein, int socket) int nread; while (fgets(sendbuff, MAXLINE, filein) != NULL) { FullWrite(socket, sendbuff, strlen(sendbuff)); - nread = FullRead(socket, recvbuff, strlen(sendbuff)); + nread = read(socket, recvbuff, strlen(sendbuff)); recvbuff[nread] = 0; fputs(recvbuff, stdout); } diff --git a/sources/TCP_echod.c b/sources/TCP_echod.c index 0491557..83d0c73 100644 --- a/sources/TCP_echod.c +++ b/sources/TCP_echod.c @@ -26,7 +26,7 @@ * * Usage: echod -h give all info * - * $Id: TCP_echod.c,v 1.8 2003/07/27 14:28:19 piccardi Exp $ + * $Id: TCP_echod.c,v 1.9 2003/07/27 23:41:04 piccardi Exp $ * ****************************************************************/ /* @@ -41,7 +41,7 @@ #include /* syslog system functions */ #include /* signal functions */ #include /* error code */ -#include /* error code */ +#include /* error strings */ #include "Gapil.h" #define BACKLOG 10 @@ -209,7 +209,7 @@ void ServEcho(int sockfd) { } } nwrite = FullWrite(sockfd, buffer, nread); - if (nwrite < 0) { + if (nwrite) { snprintf(debug, MAXLINE+20, "Errore in scrittura: %s \n", strerror(errno)); if (demonize) { /* daemon mode */ @@ -234,8 +234,8 @@ void ServEcho(int sockfd) { * routine to print error on stout or syslog */ void PrintErr(char * error) { - if (demonize) { /* daemon mode */ - syslog(LOG_ERR, error); + if (demonize) { /* daemon mode */ + syslog(LOG_ERR, "%s: %m", error); /* log string and error message */ } else { perror(error); } diff --git a/sources/TCP_echod_first.c b/sources/TCP_echod_first.c index 55fd5c6..b1356fe 100644 --- a/sources/TCP_echod_first.c +++ b/sources/TCP_echod_first.c @@ -1,4 +1,4 @@ -/* TCP_echod.c +/* TCP_echod_first.c * * Copyright (C) 2001-2003 Simone Piccardi * @@ -26,7 +26,7 @@ * * Usage: echod -h give all info * - * $Id: TCP_echod_first.c,v 1.1 2003/05/06 14:05:12 piccardi Exp $ + * $Id: TCP_echod_first.c,v 1.2 2003/07/27 23:41:04 piccardi Exp $ * ****************************************************************/ /* @@ -40,12 +40,14 @@ #include #include /* syslog system functions */ #include /* signal functions */ +#include /* error code */ +#include /* error strings */ #include "Gapil.h" #define BACKLOG 10 #define MAXLINE 256 -int demonize = 1; /* daemon use option */ -int debugging = 0; /* debug info printing option */ +int demonize = 1; /* daemon use option: default is daemon */ +int debugging = 0; /* debug info printing option: default is no debug */ /* Subroutines declaration */ void usage(void); void ServEcho(int sockfd); @@ -179,14 +181,8 @@ void ServEcho(int sockfd) { /* main loop, reading 0 char means client close connection */ while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) { nwrite = FullWrite(sockfd, buffer, nread); - if (debugging) { - buffer[nread] = 0; - snprintf(debug, MAXLINE+20, "Letti %d byte, %s", nread, buffer); - if (demonize) { /* go daemon */ - syslog(LOG_DEBUG, debug); - } else { - printf("%s", debug); - } + if (nwrite) { + PrintErr("write error"); } } return; @@ -195,8 +191,8 @@ void ServEcho(int sockfd) { * routine to print error on stout or syslog */ void PrintErr(char * error) { - if (demonize) { /* go daemon */ - syslog(LOG_ERR, error); + if (demonize) { /* daemon mode */ + syslog(LOG_ERR, "%s: %m", error); /* log string and error message */ } else { perror(error); }