Ultime modifiche
authorSimone Piccardi <piccardi@gnulinux.it>
Thu, 19 Jun 2003 14:18:27 +0000 (14:18 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Thu, 19 Jun 2003 14:18:27 +0000 (14:18 +0000)
elemtcp.tex
listati/TCP_echod.c
sources/TCP_echod.c

index 29fa8456a9b82ffb4d1e8a7ccf208bb518ec1842..788fc169533773f412ca0214390271c4133e6bc0 100644 (file)
@@ -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 
 
 
 
index 3f17baaadca46d4b39da87610dc3ceeede1ca9b2..d5c8bba93c29bd192f8021ec45ca687c036582a6 100644 (file)
@@ -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 */
 }
index d75fd1febc6000fdec5c3dba2cd13a5b0e2755ab..576c47f2069ac3d03bcd2b177af409d20f9c9bdb 100644 (file)
@@ -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);
 }
 /*