Différences entre versions de « Php daemon »
Ligne 26 : | Ligne 26 : | ||
/** | /** | ||
* Classe permettant de répondre aux signaux système | * Classe permettant de répondre aux signaux système | ||
+ | * | ||
* @param string $name | * @param string $name | ||
− | * Le nom de la classe | + | * Le nom de la classe |
*/ | */ | ||
protected function __construct($name) { | protected function __construct($name) { | ||
Ligne 57 : | Ligne 58 : | ||
* Fonction qui s'occupe de la gestion des signaux | * Fonction qui s'occupe de la gestion des signaux | ||
* | * | ||
− | * @param string $signal | + | * @param string $signal |
*/ | */ | ||
− | + | protected function handleSignal($signal) { | |
if ($signal == SIGTERM || $signal == SIGTERM) { | if ($signal == SIGTERM || $signal == SIGTERM) { | ||
// Gestion de l'extinction | // Gestion de l'extinction | ||
− | $this-> | + | $this->onStop (); |
+ | $this->isRunning = false; | ||
} else if ($sig == SIGHUP) { | } else if ($sig == SIGHUP) { | ||
// Gestion du redémarrage | // Gestion du redémarrage | ||
− | $this->onStop(); | + | $this->onStop (); |
− | $this->onStart(); | + | $this->onStart (); |
} else if ($sig == SIGCHLD) { | } else if ($sig == SIGCHLD) { | ||
// Gestion des processus fils | // Gestion des processus fils | ||
Ligne 72 : | Ligne 74 : | ||
} else { | } else { | ||
// Gestion des autres signaux | // Gestion des autres signaux | ||
− | $this->handleOtherSignals (); | + | $this->handleOtherSignals ( $signal ); |
} | } | ||
} | } | ||
/** | /** | ||
− | * Fonction qui va permettre d'exécuter | + | * Fonction qui va permettre d'exécuter |
− | * indéfiniment la | + | * indéfiniment la fonction ''run'' |
*/ | */ | ||
− | protected function start(){ | + | protected function start() { |
− | $this->onStart(); | + | $this->onStart (); |
− | while ($this->isRunning){ | + | while ( $this->isRunning ) { |
− | $this->run(); | + | $this->run (); |
} | } | ||
} | } | ||
Ligne 99 : | Ligne 101 : | ||
/** | /** | ||
* Fonction laissée pour la gestion des autres signaux | * Fonction laissée pour la gestion des autres signaux | ||
+ | * | ||
+ | * @param string $signal | ||
*/ | */ | ||
− | protected abstract function handleOtherSignals(); | + | protected abstract function handleOtherSignals($signal); |
} | } | ||
Ligne 109 : | Ligne 113 : | ||
Cela nous permet dans la classe ''Daemon'' de seulement coder le comportement du démon et non ce qu'il fait. | Cela nous permet dans la classe ''Daemon'' de seulement coder le comportement du démon et non ce qu'il fait. | ||
+ | == Utilisation== | ||
+ | Voici une classe ''Server'' qui implémente la classe ''Daemon'' : | ||
+ | <div style="width:700px"> | ||
+ | <source lang="php" style="border:1px solid black;font-size:110%"> | ||
+ | <?php | ||
+ | class Server extends Daemon { | ||
+ | |||
+ | public function __construct(){ | ||
+ | parent::__construct("Server"); | ||
+ | // Démarrage du démon | ||
+ | parent::start(); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Fonction exécutée indéfiniment | ||
+ | */ | ||
+ | public function run(){ | ||
+ | // Le code qui s'exécute infiniment | ||
+ | echo "On tourne !\n"; | ||
+ | sleep(5); | ||
+ | } | ||
+ | /** | ||
+ | * Fonction exécutée une fois au démarrage du démon | ||
+ | */ | ||
+ | public function onStart(){ | ||
+ | echo "Démarrage du processus avec le pid ".getmypid()."\n"; | ||
+ | } | ||
+ | /** | ||
+ | * Fonction exécutée une fois à l'arrêt du démon | ||
+ | */ | ||
+ | public function onStop(){ | ||
+ | echo "Arrêt du processus avec le pid ".getmypid()."\n"; | ||
+ | } | ||
+ | /** | ||
+ | * Fonction laissée pour la gestion des autres signaux | ||
+ | */ | ||
+ | public function handleOtherSignals($signal){ | ||
+ | echo "Signal non géré par la classe Daemon : ".$signal; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </source> | ||
+ | </div> | ||
+ | Et enfin, un fichier qui nous permet d'instancier et de démarrer la classe ''Server'' : | ||
+ | <div style="width:700px"> | ||
+ | <source lang="php" style="border:1px solid black;font-size:110%"> | ||
+ | <?php | ||
+ | include_once 'class/Daemon.class.php'; | ||
+ | include_once 'class/Server.class.php'; | ||
+ | |||
+ | new Server(); | ||
+ | </source> | ||
+ | </div> | ||
+ | Lorsque vous démarrer le script dans [[Eclipse_install | Eclipse]] ou dans un terminal vous devriez voir cela : | ||
+ | <pre> | ||
+ | Démarrage du processus avec le pid 82108 | ||
+ | On tourne ! | ||
+ | On tourne ! | ||
+ | On tourne ! | ||
+ | |||
+ | </pre> | ||
+ | Et lorsque on exécute la commande suivante dans un autre terminal : | ||
+ | <pre> | ||
+ | # kill 82108 | ||
+ | </pre> | ||
+ | Le message suivant apparaît : | ||
+ | <pre> | ||
+ | Arrêt du processus avec le pid 82108 | ||
+ | </pre> | ||
== Implémentation == | == Implémentation == |
Version du 3 mars 2017 à 11:49
Introduction
Définition
Un daemon [...], parfois traduit par démon, désigne un type de programme informatique, un processus ou un ensemble de processus qui s'exécute en arrière-plan plutôt que sous le contrôle direct d'un utilisateur. Wikipedia
Principe
Pour qu'un processus soit considéré comme un démon, il faut :
- qu'il puisse répondre au signaux du système ;
- qu'il continue son exécution avec ou sans contrôle utilisateur.
Mise en place
Réception des signaux système
Nous allons créer une classe serveur qui va répondre aux interruptions envoyées par le système. Celles qui vont nous intéresser sont :
- SIGINT : signal d’interruption déclenché par ctrl+c;
- SIGTERM : signal de terminaison déclenché par la commande kill;
- SIGCHLD : signal utilisé pour gérer les processus fils (fork)
- SIGHUP : signal utilisé pour redémarrer un processus;
Nous allons créer une classe abstraite Daemon qui va nous servir de base pour répondre aux signaux :
<?php
abstract class Daemon {
protected $name;
private $isRunning = true;
/**
* Classe permettant de répondre aux signaux système
*
* @param string $name
* Le nom de la classe
*/
protected function __construct($name) {
$this->name = $name;
// Permet au script PHP de s'éxécuter indéfiniment
set_time_limit ( 0 );
$this->registerSignals ();
}
/**
* Fonction qui permet l'enregistrement des signaux
*/
private function registerSignals() {
declare ( ticks = 1 )
;
pcntl_signal ( SIGTERM, array (
'Daemon',
'handleSignal'
) );
pcntl_signal ( SIGINT, array (
'Daemon',
'handleSignal'
) );
pcntl_signal ( SIGCHLD, array (
'Daemon',
'handleSignal'
) );
}
/**
* Fonction qui s'occupe de la gestion des signaux
*
* @param string $signal
*/
protected function handleSignal($signal) {
if ($signal == SIGTERM || $signal == SIGTERM) {
// Gestion de l'extinction
$this->onStop ();
$this->isRunning = false;
} else if ($sig == SIGHUP) {
// Gestion du redémarrage
$this->onStop ();
$this->onStart ();
} else if ($sig == SIGCHLD) {
// Gestion des processus fils
pcntl_waitpid ( - 1, $status, WNOHANG );
} else {
// Gestion des autres signaux
$this->handleOtherSignals ( $signal );
}
}
/**
* Fonction qui va permettre d'exécuter
* indéfiniment la fonction ''run''
*/
protected function start() {
$this->onStart ();
while ( $this->isRunning ) {
$this->run ();
}
}
/**
* Fonction exécutée indéfiniment
*/
protected abstract function run();
/**
* Fonction exécutée une fois au démarrage du démon
*/
protected abstract function onStart();
/**
* Fonction exécutée une fois à l'arrêt du démon
*/
protected abstract function onStop();
/**
* Fonction laissée pour la gestion des autres signaux
*
* @param string $signal
*/
protected abstract function handleOtherSignals($signal);
}
?>
La classe Daemon ne peut pas être instanciée car elle est abstraite ce qui permet de définir les méthodes abstraites onStart, onStop, run et handleOtherSignals. Le code de ces méthodes est spécifique à chaque démon et c'est pour cela que l'utilisateur qui va étendre la classe Daemon devra les surcharger.
Cela nous permet dans la classe Daemon de seulement coder le comportement du démon et non ce qu'il fait.
Utilisation
Voici une classe Server qui implémente la classe Daemon :
<?php
class Server extends Daemon {
public function __construct(){
parent::__construct("Server");
// Démarrage du démon
parent::start();
}
/**
* Fonction exécutée indéfiniment
*/
public function run(){
// Le code qui s'exécute infiniment
echo "On tourne !\n";
sleep(5);
}
/**
* Fonction exécutée une fois au démarrage du démon
*/
public function onStart(){
echo "Démarrage du processus avec le pid ".getmypid()."\n";
}
/**
* Fonction exécutée une fois à l'arrêt du démon
*/
public function onStop(){
echo "Arrêt du processus avec le pid ".getmypid()."\n";
}
/**
* Fonction laissée pour la gestion des autres signaux
*/
public function handleOtherSignals($signal){
echo "Signal non géré par la classe Daemon : ".$signal;
}
}
Et enfin, un fichier qui nous permet d'instancier et de démarrer la classe Server :
<?php
include_once 'class/Daemon.class.php';
include_once 'class/Server.class.php';
new Server();
Lorsque vous démarrer le script dans Eclipse ou dans un terminal vous devriez voir cela :
Démarrage du processus avec le pid 82108 On tourne ! On tourne ! On tourne !
Et lorsque on exécute la commande suivante dans un autre terminal :
# kill 82108
Le message suivant apparaît :
Arrêt du processus avec le pid 82108