From 7f87146842e5e91ef5335ff7a44e0d6d622812f0 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 2 Aug 2003 19:54:11 +0000 Subject: [PATCH] Continuo a riordinare gli esempi. --- elemtcp.tex | 107 +++++++++++++++++-------- listati/ServEcho.c | 19 ----- listati/TCP_echod_second.c | 18 ++++- sources/ElemEchoTCPClient.c | 129 ------------------------------ sources/ElemEchoTCPServer.c | 154 ------------------------------------ sources/TCP_echod.c | 18 +++-- 6 files changed, 105 insertions(+), 340 deletions(-) delete mode 100644 listati/ServEcho.c delete mode 100644 sources/ElemEchoTCPClient.c delete mode 100644 sources/ElemEchoTCPServer.c diff --git a/elemtcp.tex b/elemtcp.tex index b1748ca..da7219c 100644 --- a/elemtcp.tex +++ b/elemtcp.tex @@ -2037,9 +2037,11 @@ il pi richiedere il riavvio automatico delle system call interrotte secondo la semantica di BSD, usando l'opzione \const{SA\_RESTART} di \func{sigaction}; rispetto a quanto visto in \figref{fig:sig_Signal_code}. Definiremo allora la -nuova funzione \func{SignalRestart} come mostrato in -\figref{fig:sig_SignalRestart_code}, ed installeremo il gestore usando -quest'ultima. +nuova funzione \func{SignalRestart}\footnote{anche questa è definita, insieme + alle altre funzioni riguardanti la gestione dei segnali, nel file + \file{SigHand.c}, il cui contento completo può essere trovato negli esempi + allegati.} come mostrato in \figref{fig:sig_SignalRestart_code}, ed +installeremo il gestore usando quest'ultima. \begin{figure}[!htb] \footnotesize \centering @@ -2054,12 +2056,12 @@ quest'ultima. \end{figure} Come si può notare questa funzione è identica alla precedente \func{Signal}, -solo che in questo caso invece di inizializzare a zero il campo -\var{sa\_flags} di \struct{sigaction}, lo si inizializza (\texttt{\small 5}) -al valore \const{SA\_RESTART}. Usando questa funzione al posto di -\func{Signal} nel server non è necessaria nessuna altra modifica: le system -call interrotte saranno automaticamente riavviate, e l'errore \errcode{EINTR} -non si manifesterà più. +illustrata in \figref{fig:sig_Signal_code}, solo che in questo caso invece di +inizializzare a zero il campo \var{sa\_flags} di \struct{sigaction}, lo si +inizializza (\texttt{\small 5}) al valore \const{SA\_RESTART}. Usando questa +funzione al posto di \func{Signal} nel server non è necessaria nessuna altra +modifica: le system call interrotte saranno automaticamente riavviate, e +l'errore \errcode{EINTR} non si manifesterà più. La seconda soluzione è più invasiva e richiede di controllare tutte le volte l'errore restituito dalle varie system call, ripetendo la chiamata qualora @@ -2071,11 +2073,32 @@ Inoltre in certi casi,\footnote{Stevens in \cite{UNP1} accenna che la maggior parte degli Unix derivati da BSD non fanno ripartire \func{select}; altri non riavviano neanche \func{accept} e \func{recvfrom}, cosa che invece nel caso di Linux viene sempre fatta.} 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}, dove si è riportata la sezione di codice -modificata per la seconda versione del programma, che si trova nel file -\file{}. +detto possa essere usata con \func{accept}. + + +La portabilità nella gestione dei segnali però viene al costo di una +riscrittura parziale del server, la nuova versione di questo, in cui si sono +introdotte una serie di nuove opzioni che ci saranno utili per il debug, è +mostrata in \figref{fig:TCP_echo_server_code_second}, dove si sono riportate +la sezioni di codice modificate nella seconda versione del programma, il +sorgente completo di quest'ultimo si trova nel file +\file{TCP\_echod\_second.c} dei sorgenti allegati alla guida. + +La prima modifica effettuata è stata quella di introdurre una nuova opzione a +riga di comando, \texttt{-c}, che permette di richiedere il comportamento +compatibile nella gestione di \const{SIGCHLD} al posto della semantica BSD +impostando la variabile \var{compat} ad un valore non nullo. Questa è +preimpostata al valore nullo, cosicché se non si usa questa opzione il +comportamento di default del server è di usare la semantica BSD. + +Una seconda opzione aggiunta è quella di inserire un tempo di attesa fisso +specificato in secondi fra il ritorno della funzione \func{listen} e la +chiamata di \func{accept}, specificabile con l'opzione \texttt{-w}, che +permette di impostare la variabile \var{waiting}. Infine si è introdotta una +opzione \texttt{-d} per abilitare il debugging che imposta ad un valore non +nullo la variabile \var{debugging}. Al solito la gestione di tutte queste +opzioni si è omessa da \figref{fig:TCP_echo_server_code_second}, ma può essere +visionata nel sorgente del programma. \begin{figure}[!htb] \footnotesize \centering @@ -2086,35 +2109,55 @@ modificata per la seconda versione del programma, che si trova nel file \caption{La sezione nel codice della seconda versione del server per il servizio \textit{echo} modificata per tener conto dell'interruzione delle system call.} - \label{fig:TCP_echo_server_code} + \label{fig:TCP_echo_server_code_second} \end{figure} -In realtà l'unica chiamata critica che può essere interrotta nel server è -quella ad \func{accept}, dato che questa è l'unica che può mettere il processo -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 sostanziale nella nuova versione del server, rispetto -alla versione precedente vista in \figref{fig:TCP_ServEcho_first}, è nella -sezione (\texttt{\small 9--14}) in cui si effettua la chiamata di -\func{accept}. Quest'ultima viene effettuata (\texttt{\small 9--10}) +Vediamo allora come è cambiato il nostro server; una volta definite le +variabili e trattate le opzioni il primo passo (\texttt{\small 9--13}) è +verificare la semantica scelta per la gestione di \const{SIGCHLD}, a seconda +del valore di \var{compat} (\texttt{\small 9}) si installa il gestore con la +funzione \func{Signal} (\texttt{\small 10}) o con \texttt{SignalRestart} +(\texttt{\small 12}), essendo quest'ultimo il valore di default. + +Tutta la sezione seguente, che crea il socket, cede i privilegi di +amministratore ed eventualmente lancia il programma come demone, è rimasta +invariata e pertanto non la si è riportata in +\figref{fig:TCP_echo_server_code_second}; l'unica modifica effettuata è stata +quella di aver introdotto (\texttt{\small 21}) l'eventuale pausa specificata +con l'opzione \code{-w Nsec}, che inizializza la variabile \var{waiting} al +numero di secondi da aspettare, subito dopo la chiamata (\texttt{\small + 17--20}) alla funzione \func{listen}. + +Si è potuto far questo perché l'unica chiamata critica che può essere +interrotta da \const{SIGCHLD} nel server è quella ad \func{accept}, che è +l'unica funzione che può mettere il processo 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 sostanziale ciclo principale (\texttt{\small + 23--42}) rispetto precedente versione di \figref{fig:TCP_ServEcho_first}, è +nella sezione (\texttt{\small 26--30}) in cui si effettua la chiamata di +\func{accept}. Quest'ultima viene effettuata (\texttt{\small 26--27}) 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}), +altri casi si esce in caso di errore effettivo (\texttt{\small 27--29}), 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}. +(\texttt{\small 31--39}) di aiuto per il debug del programma, che eseguita con +un controllo (\texttt{\small 31}) sul valore della variabile \var{debugging} +impostato dall'opzione \texttt{-d}. Qualora questo sia nullo, come +preimpostato, non accade nulla. altrimenti (\texttt{\small 32}) l'indirizzo +ricevuto da \var{accept} viene convertito in una stringa che poi +(\texttt{\small 33--38}) viene opportunamente stampata o sullo schermo o nei +log. + diff --git a/listati/ServEcho.c b/listati/ServEcho.c deleted file mode 100644 index 686c14a..0000000 --- a/listati/ServEcho.c +++ /dev/null @@ -1,19 +0,0 @@ -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 (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); - } - } - } - return; -} diff --git a/listati/TCP_echod_second.c b/listati/TCP_echod_second.c index d5c8bba..78557af 100644 --- a/listati/TCP_echod_second.c +++ b/listati/TCP_echod_second.c @@ -1,7 +1,23 @@ int main(int argc, char *argv[]) { ... + int waiting = 0; + int compat = 0; ... + + /* Main code begin here */ + if (compat) { /* install signal handler */ + Signal(SIGCHLD, HandSigCHLD); /* non restarting handler */ + } else { + SignalRestart(SIGCHLD, HandSigCHLD); /* restarting handler */ + } + ... + + /* main body */ + if (listen(list_fd, BACKLOG) < 0 ) { + PrintErr("listen error"); + exit(1); + } if (waiting) sleep(waiting); /* handle echo to client */ while (1) { @@ -22,7 +38,7 @@ int main(int argc, char *argv[]) } } /* fork to handle connection */ - ... ... } + return; } diff --git a/sources/ElemEchoTCPClient.c b/sources/ElemEchoTCPClient.c deleted file mode 100644 index 942b21a..0000000 --- a/sources/ElemEchoTCPClient.c +++ /dev/null @@ -1,129 +0,0 @@ -/* ElemEchoTCPClient.c - * - * Copyright (C) 2001 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 ElemEchoTCPClient.c - * Simple TCP client for echo service (port 7) - * - * Author: Simone Piccardi - * Jun. 2001 - * - * Usage: echo -h give all info's - * - * $Id: ElemEchoTCPClient.c,v 1.8 2003/05/02 09:55:13 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 */ - -#define MAXLINE 256 -void usage(void); -void ClientEcho(FILE * filein, int socket); - -/* Program begin */ -int main(int argc, char *argv[]) -{ -/* - * Variables definition - */ - int sock_fd, 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(0); - 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_fd = socket(AF_INET, SOCK_STREAM, 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; - } - /* extablish connection */ - if (connect(sock_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) { - perror("Connection error"); - return -1; - } - /* read daytime from server */ - ClientEcho(stdin, sock_fd); - /* 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(" -h print this help\n"); - exit(1); -} - -void ClientEcho(FILE * filein, int socket) -{ - char sendbuff[MAXLINE], recvbuff[MAXLINE]; - int nread; - while (fgets(sendbuff, MAXLINE, filein) != NULL) { - FullWrite(socket, sendbuff, strlen(sendbuff)); - nread = FullRead(socket, recvbuff, strlen(sendbuff)); - recvbuff[nread] = 0; - fputs(recvbuff, stdout); - } - return; -} diff --git a/sources/ElemEchoTCPServer.c b/sources/ElemEchoTCPServer.c deleted file mode 100644 index fa77ff0..0000000 --- a/sources/ElemEchoTCPServer.c +++ /dev/null @@ -1,154 +0,0 @@ -/* ElemEchoTCPServer.c - * - * Copyright (C) 2001 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 echod - * Elementary TCP server for echo service (port 7) - * - * Author: Simone Piccardi - * Jun. 2001 - * - * Usage: echod -h give all info - * - * $Id: ElemEchoTCPServer.c,v 1.7 2003/05/02 09:55:13 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 - - -#define BACKLOG 10 -#define MAXLINE 256 - -/* Subroutines declaration */ -void usage(void); -void ServEcho(int sockfd); -/* Program beginning */ -int main(int argc, char *argv[]) -{ -/* - * Variables definition - */ - int list_fd, conn_fd; - pid_t pid; - struct sockaddr_in serv_add; - /* - * Input section: decode parameters passed in the calling - * Use getopt function - */ - int i; - 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(0); - 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 ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - perror("Socket creation error"); - exit(-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 */ - serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */ - /* bind socket */ - if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) { - perror("bind error"); - exit(-1); - } - /* listen on socket */ - if (listen(list_fd, BACKLOG) < 0 ) { - perror("listen error"); - exit(-1); - } - /* handle echo to client */ - while (1) { - /* accept connection */ - if ( (conn_fd = accept(list_fd, NULL, NULL)) < 0) { - perror("accept error"); - exit(-1); - } - /* fork to handle connection */ - if ( (pid = fork()) < 0 ){ - perror("fork error"); - exit(-1); - } - if (pid == 0) { /* child */ - close(list_fd); /* close listening socket */ - SockEcho(conn_fd); /* handle echo */ - exit(0); - } else { /* parent */ - close(conn_fd); /* close connected socket */ - } - } - /* normal exit, never reached */ - exit(0); -} -/* - * routine to print usage info and exit - */ -void usage(void) { - printf("Elementary echo server\n"); - printf("Usage:\n"); - printf(" echod [-h] \n"); - printf(" -h print this help\n"); - exit(1); -} -/* - * routine to handle echo for connection - */ -void ServEcho(int sockfd) { - char buffer[MAXLINE]; - int nread, nwrite; - - /* main loop, reading 0 char means client close connection */ - while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) { - printf("Letti %d bytes, %s ", nread, buffer); - nwrite = FullWrite(sockfd, buffer, nread); - } - return; -} diff --git a/sources/TCP_echod.c b/sources/TCP_echod.c index 25a4571..fe14ea3 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.10 2003/07/29 22:41:36 piccardi Exp $ + * $Id: TCP_echod.c,v 1.11 2003/08/02 19:54:11 piccardi Exp $ * ****************************************************************/ /* @@ -60,6 +60,7 @@ int main(int argc, char *argv[]) */ int list_fd, conn_fd; int waiting = 0; + int compat = 0; pid_t pid; struct sockaddr_in serv_add, cli_add; socklen_t len; @@ -70,7 +71,7 @@ int main(int argc, char *argv[]) */ int i; opterr = 0; /* don't want writing to stderr */ - while ( (i = getopt(argc, argv, "hdiw:")) != -1) { + while ( (i = getopt(argc, argv, "hdicw:")) != -1) { switch (i) { /* * Handling options @@ -83,6 +84,9 @@ int main(int argc, char *argv[]) case 'i': demonize = 0; break; + case 'c': + compat = 1; + break; case 'd': debugging = 1; break; @@ -103,8 +107,12 @@ int main(int argc, char *argv[]) * Main code beginning * * ***********************************************************/ - /* install SIGCHLD handler */ - SignalRestart(SIGCHLD, HandSigCHLD); /* establish handler */ + /* Main code begin here */ + if (compat) { /* install signal handler */ + Signal(SIGCHLD, HandSigCHLD); /* non restarting handler */ + } else { + SignalRestart(SIGCHLD, HandSigCHLD); /* restarting handler */ + } /* create socket */ if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("Socket creation error"); @@ -186,6 +194,7 @@ void usage(void) { printf(" -h print this help\n"); printf(" -d write debug info\n"); printf(" -i use interactively\n"); + printf(" -c disable BSD semantics\n"); printf(" -w N wait N sec. before calling accept\n"); exit(1); } @@ -196,7 +205,6 @@ void ServEcho(int sockfd) { char buffer[MAXLINE]; int nread, nwrite; char debug[MAXLINE+20]; - int size; /* main loop, reading 0 char means client close connection */ while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) { if (nread < 0) { -- 2.30.2