/** * Daemonize * * Several rules or characteristics that most daemons possess: * 1) Check is daemon already running * 2) Fork child process * 3) Sets identity * 4) Make current process a session laeder * 5) Write process ID to file * 6) Change home path * 7) umask(0) * * @access private * @since 1.0 * @return void */ function _daemonize() { ob_end_flush();
if ($this->_isDaemonRunning()) { // Deamon is already running. Exiting return false; }
if (!$this->_fork()) { // Coudn't fork. Exiting. return false; }
if (!$this->_setIdentity() && $this->requireSetIdentity) { // Required identity set failed. Exiting return false; }
if (!posix_setsid()) { $this->_logMessage('Could not make the current process a session leader', DLOG_ERROR);
return false; }
if (!$fp = @fopen($this->pidFileLocation, 'w')) { $this->_logMessage('Could not write to PID file', DLOG_ERROR);
/** * Sets identity of a daemon and returns result * * @access private * @since 1.0 * @return bool */ function _setIdentity() { if (!posix_setgid($this->groupID) || !posix_setuid($this->userID)) { $this->_logMessage('Could not set identity', DLOG_WARNING);
return false; } else { return true; } }
/** * Signals handler * * @access public * @since 1.0 * @return void */ function sigHandler($sigNo) { switch ($sigNo) { case SIGTERM: // Shutdown $this->_logMessage('Shutdown signal'); exit(); break;
case SIGCHLD: // Halt $this->_logMessage('Halt signal'); while (pcntl_waitpid(-1, $status, WNOHANG) > 0); break; } }
/** * Releases daemon pid file * This method is called on exit (destructor like) * * @access public * @since 1.0 * @return void */ function releaseDaemon() { if ($this->_isChildren && file_exists($this->pidFileLocation)) { $this->_logMessage('Releasing daemon');
Klasa TestDaemon rozszeza podstawowa klase Daemon i nadpisuje dwie metody: _doTask() i _logMessage().
_doTask() - jest caly czas uruchamiana w petli przez demona. W przykladzie TestDaemon w metodzie tej utworzylem zmienna statyczna $i, ktora nie zmienia swojej wartosci po wyjsciu z funkcji. sleep(1) posluzyl mi do opoznienia dzialania znajdujacego sie dalej kodu o jedna sekunde. Jezeli nie ustawimy chociaz usleep(100) [albo mniej] - czyli 1 dziesiatej sekundy - wtedy zuzycie procesora bedzie bliskie 99% gdyz demon caly czas wykonuje jedna funkcje w petli, a ta moze sie wykonac tysiace razy w ciagu jednej sekundy, w zaleznosci od szybkosci sprzetu. Jako, ze nie potrzebujemy tylu wywolan tej funkcji podczas jednej sekundy dajemy opoznienie. W dalszej czesci metody widac, ze do momentu az $i nie osiagnie 30 dalej pozwalamy demonowi dzialac. W efekcie po 30 sekundach zostanie zamkniety daemon.
_logMessage() - sluzy nam do logowania zdarzen klasy Deamon
Potrzebny bedzie nam jeszcze jeden plik, ktory odpali nam caly przyklad:
Zauwazcie, ze po jego uruchomieniu odrazu wrocimy do obszaru wpisywania polecen w konsoli. Tak sie dzieje gdyz podczas rozdzielenia procesu na dwa (dwa identyczne rozniace sie numerkami procesu), nastepuje zamkniecie procesu rodzica - czyli tego, ktory zostal uruchomiony spod konsoli - a proces dziecka, nadal dziala w tle.
Caly proces dzialania mozemy przesledzic czytajac logi demona. Najlatwiej bedzie nam na bierzaco odczytywac plik daemon.log przy uzyciu komendy tail w wierszu polecen:
Kod
tail -f /tmp/daemon.log
I to wzasadzie tyle. Teraz tylko trzeba wymyslic cos ciekawego i zaprzasc demona do pracy. Mysle, ze mozna by nawet pokusic sie o napisanie wlasnego serwera WWW w php wlasnie w oparciu o ta klase.