From: Simone Piccardi Date: Thu, 13 Jun 2002 19:11:21 +0000 (+0000) Subject: Si prosegue X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=c4ee73fb823eafce8bb5e4faa9caebc4105dbb17;hp=30a6a42996cb5bf0d7c0b2b607743893dc964cdd Si prosegue --- diff --git a/ipc.tex b/ipc.tex index 352a719..7dd8c67 100644 --- a/ipc.tex +++ b/ipc.tex @@ -65,7 +65,7 @@ buffer nel kernel, la cui dimensione funzionamento di una pipe è illustrato in \figref{fig:ipc_pipe_singular}, in cui sono illustrati i due capi della pipe, associati a ciascun file descriptor, con le frecce che indicano la direzione del flusso dei dati -attaverso la pipe. +attraverso la pipe. \begin{figure}[htb] \centering @@ -114,23 +114,163 @@ di un'altro. Realizzaremo il programma nella forma di un per apache, che genera una immagine JPEG di un codice a barre, specificato come parametro di input. -Per fare questo useremo i programmi \cmd{barcode} e \cmd{gs}, il primo infatti -è in grado di generare immagini postscript di codici a barre corrispondenti ad -una qualunque stringa, data come parametro, mentre il secondo è in grado di -convertire un file postscript in una immagine JPEG. Usando l'ouptut del primo -come input del secondo attraverso una pipe potremo generare immagini JPEG del -codice a barre di una stringa qualunque. - -Si potrebbe obiettare che sarebbe molto più semplice ottenere lo stesso -risultato salvando il tutto in un file temporaneo, ma si dovrebbe comunque -risolvere il problema di come comunicare il nome di questo file da un processo -all'altro, dato che utilizzare lo stesso file porterebbe ad inevitabili -sovrascritture nell'accavallarsi di diversi processi. L'uso di una pipe -permette di risolvere il problema in maniera semplice ed elegante. +Un programma che deve essere eseguito come \textit{cgi-bin} per apache deve +rispondere a delle caratteristiche specifiche, esso infatti non viene lanciato +da una shell, ma dallo stesso web server, alla richiesta di una specifica URL +che di solito ha la forma: +\begin{verbatim} +http://www.sito.it/cgi-bin/programma?parametro +\end{verbatim} +ed il risultato dell'elaborazione deve essere presentato (con una intestazione +che ne descrive il mime-type) sullo standard output, in modo che apache possa +reinviarlo al browser che ha effettuato la richiesta. + + +Per fare questo useremo in sequenza i programmi \cmd{barcode} e \cmd{gs}, il +primo infatti è in grado di generare immagini postscript di codici a barre +corrispondenti ad una qualunque stringa, mentre il secondo serve per poter +effettuare la conversione della stessa immagine in formato JPEG. + +Si potrebbe obiettare che sarebbe molto più semplice salvare il risultato +intermedio su un file temporaneo. Questo però non tiene conto del fatto che il +\textit{cgi-bin} deve poter gestire più richieste in concorrenza, e si avrebbe +una evidente race condition in caso di accesso simultaneo a detto +file.\footnote{la questione potrebbe essere evitata creando prima dei file + temporanei, da comunicare poi ai vari processi, e da cancellare alla fine + dell'esecuzione; ma a questo punto avremmo perso tutta la semplicità.} L'uso +di una pipe invece permette di risolvere il problema in maniera semplice ed +elegante. Il programma ci servirà anche come esempio dell'uso di alcune delle funzioni -di manipolazione dei file descriptor, come \func{dup} e \func{dup2}, viste in -\secref{sec:file_dup} +di manipolazione dei file descriptor, come \func{dup} e \func{dup2}, viste in +\secref{sec:file_dup}; è attraverso queste funzioni che è possibile dirottare +gli stream standard dei processi (che abbiamo visto in +\secref{sec:file_std_descr} e \secref{sec:file_std_stream}) sulla pipe. Le +sezioni significative del programma è riportato in +\figref{fig:ipc_barcode_code}, il codice è disponibile nel file +\file{BarCode.c} nella directory dei sorgenti. + + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}{} +int main(int argc, char *argv[], char *envp[]) +{ + ... + /* create two pipes to handle process communication */ + if ( (retval = pipe(pipein)) ) { + WriteMess("input pipe creation error"); + exit(0); + } + if ( (retval = pipe(pipeout)) ) { + WriteMess("output pipe creation error"); + exit(0); + } + /* fork child to run barcode program */ + pid = fork(); + if (pid == -1) { + WriteMess("child creation error"); + exit(0); + } + /* if child */ + if (pid == 0) { + close(pipein[1]); /* close output side of input pipe */ + dup2(0, pipein[0]); /* remap stdin in pipe input */ + close(pipeout[0]); /* close input side of output pipe */ + dup2(1, pipeout[1]); /* remap stdout in pipe output */ + execlp("barcode", "barcode", "-E", NULL); + } else { + /* first set the pipe */ + close(pipein[0]); /* close input side of input pipe */ + close(pipeout[1]); /* close output side of output pipe */ + write(pipein[1], argv[1], strlen(argv[1])); + close(pipein[1]); + waitpid(pid, NULL, 0); + pid = fork(); + if (pid == -1) { + WriteMess("child creation error") + exit(0); + } + if (pid == 0) { + /* send mime type */ + write(0,content, strlen(content)); + dup2(0, pipeout[0]); + execlp("gs", "gs", "-sDEVICE=jpeg", "-sOutputFile=-", "-", NULL); + } else { + close(pipeout[0]); + waitpid(pid, NULL, 0); + } + } + exit(0); +} + \end{lstlisting} + \end{minipage} + \normalsize + \caption{Codice del \textit{cgi-bin} \cmd{BarCode}.} + \label{fig:ipc_barcode_code} +\end{figure} + + +Il primo passo (\texttt{\small 4-12}) è quello di creare le due pipe, una per +l'input e l'altra per l'output, che servono per la comunicazione con i due +programmi che verranno utilizzati, inviando in caso di errore (attraverso una +apposita funzione \func{WriteMess}, non riportata in +\ref{fig:ipc_barcode_code}, che si incarica di formattare l'output in HTML +perché sia interpretabile da un browser) un messaggio invece dell'immagine +richiesta. + +Una volta create le pipe il programma può creare (\texttt{\small 13-18}) il +primo processo figlio, che si incaricherà (\texttt{\small 19-25}) di eseguire +\cmd{barcode}: quest'ultimo funziona ricevendo dallo standard input la stringa +da convertire nell'immagine postscript del codice a barre che sarà scritta +sullo standard output. + +Per questo il processo figlio prima chiude (\texttt{\small 21}) il capo aperto +in scrittura della prima pipe (che sarà usato dal padre per trasmettergli la +stringa da codificare), e poi collega (\texttt{\small 22}) il capo il lettura +allo standard input usando \func{dup2}. Analogamente il capo in lettura della +seconda pipe sarà chiuso mentre il capo in scrittura viene collegato allo +standard output (\texttt{\small 23-24}. In questo modo all'esecuzione +(\texttt{\small 25}) di \cmd{barcode} quest'ultimo leggerà la stringa da +codificare dalla prima pipe e scriverà l'immagine postscript nella seconda. + +Dall'altra parte il processo padre prima chiude (\texttt{\small 28-29}) i due +capi inutilizzati delle pipe (input della prima ed output della seconda), poi +scrive (\texttt{\small 30}) la stringa da convertire sull'output della prima +pipe così che \cmd{barcode} possa riceverla dallo standard input; a questo +punto l'uso della prima pipe è finito ed essa può essere definitivamente +chiusa (\texttt{\small 31}), si attenderà poi (\texttt{\small 32}) che pure +l'esecuzione di \cmd{barcode} venga completata. + +Alla conclusione della sua esecuzione \cmd{barcode} avrà effettuato inviato +l'immagine postscript del codice a barre sul capo in scrittura della seconda +pipe; + + + + +\subsection{Le funzioni \func{popen} e \func{pclose}} +\label{sec:ipc_popen} + +Come si è visto la modalità più comune di utilizzo di una pipe è quella di +utilizzarla per fare da tramite fra output ed input di due programmi invocati +in sequenza; per questo motivo lo standard POSIX.2 ha introdotto due funzioni +che permettono di sintetizzare queste operazioni comuni in una sola +chiamata. La prima di esse si chiama \func{popen} ed il suo prototipo è: + + +L'esempio in \figref{fig:ipc_barcode_code} per quanto perfettamente +funzionante, è piuttosto complesso; inoltre nella pratica sconta un problema +di \cmd{gs} che non è in grado\footnote{nella versione GNU Ghostscript 6.53 + (2002-02-13).} di riconoscere correttamente l'encapsulated postscript, per +cui tutte le volte generata una pagina intera, invece che una semplice figura. +Se si vuole generare una immagine di dimensioni corrette si deve allora +ricorrere ad ulteriore programma, \cmd{epstopsf}, per convertire in PDF il +file EPS generato da \cmd{barcode}, che invece viene trattato correttamente. + + + @@ -138,7 +278,7 @@ di manipolazione dei file descriptor, come \func{dup} e \func{dup2}, viste in \label{sec:ipc_named_pipe} Per poter superare il problema delle \textit{pipe}, illustrato in -\secref{sec:ipc_pipes}, che ne consente l'uso solo fra procesi con un +\secref{sec:ipc_pipes}, che ne consente l'uso solo fra processi con un progenitore comune o nella relazione padre/figlio, lo standard POSIX.1 definisce dei nuovi oggetti, le \textit{fifo}, che invece possono risiedere sul filesystem, e che i processi possono usare per le comunicazioni senza @@ -152,7 +292,7 @@ dovere per forza essere in relazione diretta. Per ovviare ai vari limiti dei meccanismo tradizionale di comunicazione fra processi visto in \secref{sec:ipc_unix}, nello sviluppo di System V vennero -introdotti una serie di nuovi oggetti e relative interdacce che garantissero +introdotti una serie di nuovi oggetti e relative interfacce che garantissero una maggiore flessibilità; in questa sezione esamineremo quello che viene ormai chiamato il \textit{System V Inter-Process Comunication System}, più comunemente noto come \textit{SystemV IPC}.