//Esempio di file SOLUZIONE.txt //Autore: Claudio Caraffi www.ce.unipr.it/caraffi (contattare per chiarimenti) //Questo è un modello dei ragionamenti che dovrebbero fare e trascrivere gli studenti PRIMA di cominciare a scrivere il programma Utilizzo lo scheletro di un normale server concorrente. Il figlio che gestisce la connessione deve leggere dal client: A- Il nome di un comando unix B- Un numero variabile (da 0 a 8) di righe C- Una riga finale di stop Dopo di ché deve eseguire il comando A con come argomento un file contenente le righe del punto B. Per memorizzare il comando A utilizzo una stringa. Le righe del punto B devono essere memorizzate in un file temporaneo; per creare un file devo usare la *fopen*. Può capitare che, mentre un figlio sta memorizzando i dati nel suo file temporaneo, un altro figlio (che sta gestendo un altro client) debba fare la stessa operazione; perciò occorre fare in modo che il nome file sia unico per ognuno dei client gestiti. Per fare questo posso utilizzare come nome il *pid* del figlio stesso: per creare il nome del file utilizzo la funzione *sprintf*. Per ogni riga successiva alla prima devo verificare di non avere ricevuto la stringa STOP, per fare questo posso utilizzare *strcmp* (comparando "STOP\r\n") o *strncmp* (comparando i primi 4 caratteri con la stringa "STOP") Le righe diverse da STOP devono essere memorizzate nel file creato precedentemente. *Continuo a leggere* fino a quando ricevo STOP. Quando ricevo STOP passo all'esecuzione del comando Per eseguire il comando utilizzo la primitiva *execv* o *execvp*. Siccome le funzioni exec non ritornano, per poter poi cancellare il file devo fare compiere la exec da un figlio (nipote), e aspettare (*wait*) per poi procedere alla cancellazione del file (*unlink*) La lista degli argomenti di execv comprende il comando stesso e il nome del file creato. Per permettere la redirezione dell'output al client, prima della exec chiudo stdout e stderr ( *close(1)* e *close(2)* ) e copio il file descriptor della socket al client tramite due *dup* (NdR: Ricordiamo che la dup utilizza sempre il primo file descriptor libero) Per quanto riguarda i segnali, l'arrivo di un SIGUSR1 e di un SIGUSR2 fa cambiare di stato il server (padre): se si trova in un certo stato il padre alla connessione stampa l'indirizzo del client, se si trova nell'altro stato invece non stampa nulla. Devo quindi conservare in una *variabile globale* lo stato del server e, in base al suo valore, alla connessione decidere se stampare o meno l'indirizzo del client. Lo stato iniziale è quello che prevede di non stampare gli indirizzi dei client. La variabile globale deve essere opportunamente modificata all'interno del gestore dei segnali. Per i segnali utilizzo una gestione affidabile.