From 12b230ea57ff3a54a12d4e2226e3901a2345fb63 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Thu, 19 Jun 2003 14:18:27 +0000 Subject: [PATCH] Ultime modifiche --- elemtcp.tex | 86 ++++++++++++++++++++++++++------------------- listati/TCP_echod.c | 72 ++++++++++--------------------------- sources/TCP_echod.c | 5 +-- 3 files changed, 71 insertions(+), 92 deletions(-) diff --git a/elemtcp.tex b/elemtcp.tex index 29fa845..788fc16 100644 --- a/elemtcp.tex +++ b/elemtcp.tex @@ -2069,16 +2069,17 @@ Inoltre in certi casi,\footnote{Stevens in \cite{UNP1} accenna che la maggior di Linux questa è disponibile.} anche quando questa è presente, non è detto possa essere usata con \func{accept}. La portabilità però viene al costo di una riscrittura parziale del server, secondo quanto mostrato in -\figref{fig:TCP_echo_server_code}. +\figref{fig:TCP_echo_server_code}, dove si è riportata la sezione di codice +modificata per la seconda versione del programma. -\begin{figure}[!htbp] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15.6cm} \includecodesample{listati/TCP_echod.c} \end{minipage} \normalsize - \caption{Codice del corpo principale della seconda versione del server - per il servizio \textit{echo}.} + \caption{Sezione del codice seconda versione del server + per il servizio \textit{echo} modificate rispetto alla prima.} \label{fig:TCP_echo_server_code} \end{figure} @@ -2087,19 +2088,26 @@ quella ad \func{accept}, dato che questa padre in stato di sleep.\footnote{si noti infatti che le altre \textit{slow system call} o sono chiamate prima di entrare nel ciclo principale, quando ancora non esistono processi figli, o sono chiamate dai figli stessi.} Per -questo l'unica modifica nella nuova versione del server, rispetto alla -versione precedente vista in \figref{fig:TCP_ServEcho}, è nella sezione -(\texttt{\small 43--48}) in cui si effettua la chiamata di \func{accept}. -Quest'ultima allora viene effettuata (\texttt{\small 43--44}) all'interno di -un ciclo di \code{while}\footnote{la sintassi del C relativa a questo ciclo - può non essere del tutto chiara. In questo caso infatti si è usato un ciclo - vuoto che non esegue nessuna istruzione, in questo modo quello che viene - ripetuto con il ciclo è soltanto il codice che esprime la condizione - all'interno del \code{while}.} che la ripete indefinitamente qualora in -caso di errore il valore di \var{errno} sia \errcode{EINTR}. Negli altri casi -si esce in caso di errore effettivo (\texttt{\small 45--48}), altrimenti il -programma prosegue esattamente allo stesso modo del precedente. - +questo l'unica modifica sostanziale nella nuova versione del server, rispetto +alla versione precedente vista in \figref{fig:TCP_ServEcho}, è nella sezione +(\texttt{\small 9--14}) in cui si effettua la chiamata di \func{accept}. +Quest'ultima viene effettuata (\texttt{\small 9--10}) all'interno di un ciclo +di \code{while}\footnote{la sintassi del C relativa a questo ciclo può non + essere del tutto chiara. In questo caso infatti si è usato un ciclo vuoto + che non esegue nessuna istruzione, in questo modo quello che viene ripetuto + con il ciclo è soltanto il codice che esprime la condizione all'interno del + \code{while}.} che la ripete indefinitamente qualora in caso di errore il +valore di \var{errno} sia \errcode{EINTR}. Negli altri casi si esce in caso di +errore effettivo (\texttt{\small 11--14}), altrimenti il programma prosegue. + +Si noti che in questa nuova versione si è aggiunta una ulteriore sezione +(\texttt{\small 15--28}) per il debugging, che stampa l'indirizzo da cui si è +avuta la connessione, e la gestione (\texttt{\small 5}) di una nuova opzione, +specificabile con \code{-w Nsec}, che inizializza la variabile \var{waiting} +al numero di secondi da aspettare. Questa opzione permette di specificare un +tempo di attesa prima di passare alla chiamata \func{accept}, il cui scopo +sarà più chiaro facendo riferimento al primo degli scenari critici di +\secref{sec:TCP_echo_critical}. @@ -2114,20 +2122,18 @@ la rete gestire tutta una serie di situazioni critiche che non esistono per i processi locali. -La prima situazione critica è quella della terminazione precoce, per via di un -qualche errore di rete, della connessione effettuata da un client. Come +La prima situazione critica è quella della terminazione precoce, causata da un +qualche errore sulla rete, della connessione effettuata da un client. Come accennato in \secref{sec:TCP_func_accept} la funzione \func{accept} riporta tutti gli eventuali errori di rete pendenti su una connessione sul -\textit{connected socket}. +\textit{connected socket}. Di norma questo non è un problema a questo livello, +in quanto una volta completata la connessione \func{accept} ritorna e l'errore +sarà rilevato in seguito dal processo che la gestisce. -Questo significa che, oltre alla interruzione da parte di un segnale, che -abbiamo trattato in \secref{sec:TCP_child_hand} nel caso particolare di -\const{SIGCHLD}, si possono avere altri errori non fatali all'uscita di -\func{accept}, che necessitano semplicemente la ripetizione della chiamata -senza che si debba uscire dal programma. Uno scenario tipo è quello mostrato -in \figref{fig:TCP_early_abort}, in cui la connessione viene abortita sul lato -client con l'invio di un segmento RST, prima che nel server sia stata chiamata -la funzione \func{accept}. +In generale però è possibile incorrere anche in uno scenario del tipo di +quello mostrato in \figref{fig:TCP_early_abort}, in cui la connessione viene +abortita sul lato client con l'invio di un segmento RST, prima che nel server +sia stata chiamata la funzione \func{accept}. \begin{figure}[htb] \centering @@ -2142,23 +2148,29 @@ a quella del nostro esempio, in cui la gestione delle singole connessioni demandata a processi figli, può accadere che il three way handshake venga completato e la relativa connessione abortita subito dopo, prima che il padre, per via del carico della macchina abbia fatto in tempo a rieseguire la -chiamata \func{accept}. In questo caso si ha una situazione analoga a quella -illustrata in \figref{fig:TCP_early_abort}, la connessione viene stabilita, ma -subito dopo si ha una condizione - - -che, come nell'esempio in figura, ritornerebbe -immediatamente con un errore relativo alla connessione abortita. +chiamata \func{accept}. Di nuovo si ha una situazione analoga a quella +illustrata in \figref{fig:TCP_early_abort}, in cui la connessione viene +stabilita, ma subito dopo si ha una condizione di errore che la chiude prima +che essa sia stata accettata dal programma. +Questo significa che, oltre alla interruzione da parte di un segnale, che +abbiamo trattato in \secref{sec:TCP_child_hand} nel caso particolare di +\const{SIGCHLD}, si possono ricevere altri errori non fatali all'uscita di +\func{accept}, che come nel caso precedente, necessitano semplicemente la +ripetizione della chiamata senza che si debba uscire dal programma. In questo +caso anche la versione modificata del nostro server non sarebbe adatta, in +quanto uno di questi errori causerebbe la terminazione dello stesso. Si tenga presente che questo tipo di terminazione non è riproducibile terminando il client prima della chiamata ad \func{accept}; in tal caso infatti il socket associato alla connessione viene semplicemente chiuso, attraverso la sequenza vista in \secref{sec:TCP_conn_term}, per cui la \func{accept} ritornerà senza errori, e si avrà semplicemente un end-of-file -al primo accesso al socket. +al primo accesso al socket. Per riprodurre l'errore occorrerebbe usare +l'opzione \const{SO\_LINGER} (vedi \secref{sec:xxx}) per chiedere al client di +chiudere il socket con un segmento RST, invece che con la normale sequenza di +chiusura. -In questo caso diff --git a/listati/TCP_echod.c b/listati/TCP_echod.c index 3f17baa..d5c8bba 100644 --- a/listati/TCP_echod.c +++ b/listati/TCP_echod.c @@ -1,62 +1,28 @@ int main(int argc, char *argv[]) { - int list_fd, conn_fd; - pid_t pid; - struct sockaddr_in serv_add; ... - /* create socket */ - if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("Socket creation error"); - exit(1); - } - /* initialize address and bind socket */ - 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 */ - serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */ - if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) { - perror("bind error"); - exit(1); - } - /* give away privileges and go daemon */ - if (setgid(65534) !=0) { /* first give away group privileges */ - perror("cannot give away group privileges"); - exit(1); - } - if (setuid(65534) !=0) { /* and only after user ... */ - perror("cannot give away user privileges"); - exit(1); - } - if (demonize) { /* go daemon */ - openlog(argv[0], 0, LOG_DAEMON); /* open logging */ - if (daemon(0, 0) != 0) { - perror("cannot start as daemon"); - exit(1); - } - } - /* main body */ - if (listen(list_fd, BACKLOG) < 0 ) { /* listen on socket */ - PrintErr("listen error"); - exit(1); - } - while (1) { /* handle echo to client */ - while (((conn_fd = accept(list_fd, NULL, NULL)) < 0) - && (errno == EINTR)); /* accept connection */ - if ( conn_fd < 0) { + ... + if (waiting) sleep(waiting); + /* handle echo to client */ + while (1) { + /* accept connection */ + while (((conn_fd = accept(list_fd, (struct sockaddr *)&cli_add, &len)) + < 0) && (errno == EINTR)); + if ( conn_fd < 0) { PrintErr("accept error"); exit(1); } - if ( (pid = fork()) < 0 ) { /* fork to handle connection */ - PrintErr("fork error"); - exit(1); - } - if (pid == 0) { /* child */ - close(list_fd); /* close listening socket */ - ServEcho(conn_fd); /* handle echo */ - exit(0); - } else { /* parent */ - close(conn_fd); /* close connected socket */ + if (debugging) { + inet_ntop(AF_INET, &cli_add.sin_addr, ipaddr, sizeof(ipaddr)); + snprintf(debug, MAXLINE, "Accepted connection form %s\n", ipaddr); + if (demonize) { + syslog(LOG_DEBUG, debug); + } else { + printf("%s", debug); + } } + /* fork to handle connection */ + ... + ... } - exit(0); /* normal exit, never reached */ } diff --git a/sources/TCP_echod.c b/sources/TCP_echod.c index d75fd1f..576c47f 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.6 2003/06/19 13:29:03 piccardi Exp $ + * $Id: TCP_echod.c,v 1.7 2003/06/19 14:18:27 piccardi Exp $ * ****************************************************************/ /* @@ -183,8 +183,9 @@ void usage(void) { printf("Usage:\n"); printf(" echod [-h] \n"); printf(" -h print this help\n"); - printf(" -d print debug info\n"); + printf(" -d write debug info\n"); printf(" -i use interactively\n"); + printf(" -w N wait N sec. before calling accept\n"); exit(1); } /* -- 2.30.2