Hola a todos,
dato che stamattina ho pubblicato i sorgenti della mia classe per lo sviluppo di demoni posix e ho creato anche la pagina sul GRUSP ne approfitto per scrivere una veloce pillolina che può sempre servire a qualcuno
Premetto che la classe non fa altro che "facilitare" lo sviluppo di questo tipo di applicativi, ad esempio wrappa la funzione pcntl_fork e implementa oltre ai canonici controlli anche il supporto per sfruttare le funzioni wait e waitpid per verificare se il processo figlio termina normalmente o ha problemi. O ancora implementa un wrapper alle funzioni per settare utente/gruppo che permettono oltre a settare l'utente tramite ID (UID/GID) anche tramite nome
Il codice è compatibile ESCLUSIVAMENTE con PHP5, anche se è facile il back port a PHP4 sinceramente lo sconsiglio dato che questo non è più supportato.
Il vantaggio di questo tipo di applicativi è che è possibile integrarli con tanta roba (FAM [ www.php.net/FAM ] per la verifica delle operazioni sui dischi, integrazione per controlli su mysql, checking sui servizi di rete, interazione con le pagine web per l'esecuzione di operazioni e cosi via ... li dipende dalla vostra fantasia )
Le funzionalità implementate sono le seguenti:[list=1][*]permette di eseguire il forking del processo senza terminare il processo padre e permette di metterlo in attesa automatica per verificare se il processo figlio ha problemi durante l'esecuzione per restituire automaticamente i codici di errori relativi al blocco[*]supporta la creazione di nuove sessioni, in modo da sganciarsi dalla console o dal sistema di inizializzazione[*]grazie all'OOP è semplicissimo scrivere demoni avanzati come quello presente nel secondo esempio (OwnPosixDaemonWithParent)[*]supporta lo switching dell'utente[*]supporta i segnali posix, gli allarmi ed il ripristino dei segnali[/list=1]
Dovete scaricare il codice sorgente della classe dal mio sito, all'indirizzo
http://www.phpsoft.it/node/37
Una volta fatta l'operazione, all'interno della file ci sta oltre alla mia classe anche altre 2 classi che sono due esempi:
- OwnPosixDaemon è un esempio abbastanza base che una volta effettuato il forking del processo e creata la nuova sessione nel sistema setta la gestione di alcuni segnali e avvia il loop principale dove svolge le proprie operazioni o si mette in attesa
- OwnPosixDaemonWithParent è invece un pò più avanzato infatti prevede l'utilizzo di due processi ovvero uno controllore e un esecutore che derivano dal processo padre facendo 2 fork (il primo si sgancia dalla console facendo morire il parent mentre il child rilancia un fork lasciando due processi in esecuzione) ... il processo controllore tiene una fifo in lettura dalla quale legge i testi inviati dal processo esecutore che ogni volta che riceve un segnale USR1 manda una stringa e li visualizza a video
Qui ci sono due esempi, di seguito quello procedurale:
Codice PHP:
<?php
require_once('PosixDaemon.class.php');
$posixDaemon = new PosixDaemon();
$posixDaemon->Fork();
$posixDaemon->DetachSession();
$counter = 0;
while($counter < 5)
{
sleep(1);
$counter++;
}
exit(PosixDaemon::EXIT_OK);
?>
L'esempio invece che sfrutta l'OOP invece è qui:
Codice PHP:
<?php
require_once('PosixDaemon.class.php');
class MyPosixDaemon extendes PosixDaemon
{
public function __construct()
{
$this->Fork();
$this->DetachSession();
$this->MainLoop();
}
private function MainLoop()
{
$counter = 0;
while($counter < 5)
{
sleep(1);
$counter++;
}
exit(MyPosixDaemon::EXIT_OK);
}
}
$myPosixDaemon = new MyPosixDaemon();
?>
Com'è possibile capire, dato la semplicità, il metodo Fork si occupa di "sdoppiare" il processo clonando tutte le risorse mentre il metodo DetachSession si sgancia dalla sessione di sistema dalla quale viene lanciato e ne crea una nuova divenendone il gestore
Fatta l'operazione avvia il loop del demone che, una volta raggiungo il valore di 4 per il counter, esce senza terminare con errori o altro!
Di seguito c'è la descrizione dei vari metodi:
- Fork accetta in ingresso due valori; il primo indica al metodo fork di non terminare il processo padre e farlo quindi gestire al codice chiamate che riceve in uscita due valori PosixDaemon::FORK_ISCHILD e PosixDaemon::FORK_ISPARENT ... i due valori vengono restituiti rispettivamente se in esecuzione è il processo figlio o il processo parent; il secondo parametro indica al metodo di gestire internamente l'attesa del processo figlio per verificare se termina correttamente o se invece termina per qualche motivo particolare ovvero se qualche segnale non gestito crea problemi o se viene abortito ... alternativamente il processo padre muore restituendo il codice di uscita del processo figlio che onde evitare di avere problemi con i valori restituiti dal codice base dovrebbe essere sempre superiore almeno a 20
- DetachSession non accetta parametri in ingresso e si occupa di sganciarsi dalla sessione corrente e crea la nuova sulla quale sposta il processo
- SetUserAndGroup accetta in ingresso due parametri, di cui il secondo opzionale, e sono il nome utente o l'uid ed il nome del gruppo o il gid
- SetSignalHandler setta il gestore dei segnali posix/ansi/unix e accetta in ingresso come primo parametro il codice del segnale come singolo valore o come array di valori e come secondo parametro accetta la callback a cui passare le chiamate; la callback deve accettare un valore in entrata che corrisponde al codice del segnale ricevuto ... una sola callback può infatti gestire più segnali!
- RestoreSignalHandler ripristina i segnali passati, sempre come singolo valore o come array di valori, settando il gestore dei segnali di default
- SetAlarm accetta in ingresso il numero di secondi tra un segnale dall'allarme ed un altro e come secondo valore prende in ingresso la callback del segnale SIGALRM ... callback che è opzionale e se non passata va settata manualmente con il SetSignalHandler
- MainLoop è solo un metodo fittizzio che può essere usato come riferimento per effettuare il ciclo principale del demone
Che dire ... ho finito
PS: se avete problemi con il ripristino dei segnali o con il gestore dei segnali potrebbe essere errato il SIG_IDF nel restore ... non ho avuto modo di testarlo abbondantemente perché sinceramente ho scritto il metodo giusto per averlo ma non l'ho mai usato! Inoltre il metodo che setta utenti e gruppi utilizza is_numeric per verificare se l'uid/gid sono numerici però potrebberò esserci dei nomi utenti o nomi di gruppi numerici ed in quel caso verrebberò trattati come UID e come GID quindi il codice li andrebbe sistemato (so già come sistemarlo ... ma non ho il tempo )