守護進程(Daemon)是運行在後臺的一種特殊進程。它獨立於控制終端而且週期性地執行某種任務或等待處理某些發生的事件。守護進程是一種頗有用的進程。php也能夠實現守護進程的功能。php
最近要開發一個 Agent,由於和 webserver 一塊兒開發,因此 Agent也用PHP 開發。web
功能需求:編程
(1)需監聽端口,接收控制器發來的任務消息;session
(2)根據任務消息,啓動執行任務,並監控任務狀態;框架
(3)將任務運行結果反饋給控制器;函數
開始使用 workerman 框架,可是發現框架雖好,但也有不少限制。code
一、基本概念server
進程:每一個進程都有一個父進程,子進程退出,父進程能獲得子進程退出的狀態。繼承
進程組:每一個進程都屬於一個進程組,每一個進程組都有一個進程組號,該號等於該進程組組長的PID進程
二、守護進程編程要點
1. 在後臺運行。
爲避免掛起控制終端將Daemon放入後臺執行。方法是在進程中調用fork使父進程終止,讓Daemon在子進程中後臺執行。 if($pid=pcntl_fork()) exit(0);//是父進程,結束父進程,子進程繼續
2. 脫離控制終端,登陸會話和進程組
有必要先介紹一下Linux中的進程與控制終端,登陸會話和進程組之間的關係:進程屬於一個進程組,進程組號(GID)就是進程組長的進程號(PID)。登陸會話能夠包含多個進程組。這些進程組共享一個控制終端。這個控制終端一般是建立進程的登陸終 端。 控制終端,登陸會話和進程組一般是從父進程繼承下來的。咱們的目的就是要擺脫它們,使之不受它們的影響。方法是在第1點的基礎上,調用setsid()使進程成爲會話組長: posix_setsid();
說明:當進程是會話組長時setsid()調用失敗。但第一點已經保證進程不是會話組長。setsid()調用成功後,進程成爲新的會話組長和新的進程組長,並與原來的登陸會話和進程組脫離。因爲會話過程對控制終端的獨佔性,進程同時與控制終端脫離。
3. 重設文件建立掩模
進程從建立它的父進程那裏繼承了文件建立掩模。它可能修改守護進程所建立的文件的存取位。爲防止這一點,將文件建立掩模清除:umask(0);
umask(0)就是設置容許當前進程建立文件或者目錄最大可操做的權限,好比這裏設置爲0,它的意思就是0取反再建立文件時權限相與,也就是:(~0) & mode 等於八進制的值0777 & mode了,這樣就是給後面的代碼調用函數mkdir給出最大的權限,避免了建立目錄或文件的權限不肯定性。
<?php function daemonize() { umask(0); $pid = pcntl_fork(); if (-1 === $pid) { throw new Exception('fork fail'); } elseif ($pid > 0) { exit(0); } //Make the current process a session leader. if (-1 === posix_setsid()) { throw new Exception("setsid fail"); } // Fork again avoid SVR4 system regain the control of terminal. $pid = pcntl_fork(); if (-1 === $pid) { throw new Exception("fork fail"); } elseif (0 !== $pid) { exit(0); } }