国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Home php教程 php手冊 php寫守護進程(Daemon)

php寫守護進程(Daemon)

Jun 06, 2016 pm 07:53 PM
php process

守護進程(Daemon)是運行在后臺的一種特殊進程。它獨立于控制終端并且周期性地執(zhí)行某種任務或等待處理某些發(fā)生的事件。守護進程是一種很有用的進程。php也可以實現(xiàn)守護進程的功能。 1、基本概念 進程 每個進程都有一個父進程,子進程退出,父進程能得到子進

?守護進程(Daemon)是運行在后臺的一種特殊進程。它獨立于控制終端并且周期性地執(zhí)行某種任務或等待處理某些發(fā)生的事件。守護進程是一種很有用的進程。php也可以實現(xiàn)守護進程的功能。

?

1、基本概念

????進程

????????????每個進程都有一個父進程,子進程退出,父進程能得到子進程退出的狀態(tài)。

????進程組

????????????每個進程都屬于一個進程組,每個進程組都有一個進程組號,該號等于該進程組組長的PID

2、守護編程要點

????1. 在后臺運行。 ????
???? ????為避免掛起控制終端將Daemon放入后臺執(zhí)行。方法是在進程中調(diào)用fork使父進程終止,讓Daemon在子進程中后臺執(zhí)行。 if($pid=pcntl_fork()) exit(0);//是父進程,結(jié)束父進程,子進程繼續(xù)
????2. 脫離控制終端,登錄會話和進程組?
???????有必要先介紹一下Linux中的進程與控制終端,登錄會話和進程組之間的關(guān)系:進程屬于一個進程組,進程組號(GID)就是進程組長的進程號(PID)。登錄會話可以包含多個進程組。這些進程組共享一個控制終端。這個控制終端通常是創(chuàng)建進程的登錄終? 端。 控制終端,登錄會話和進程組通常是從父進程繼承下來的。我們的目的就是要擺脫它們,使之不受它們的影響。方法是在第1點的基礎(chǔ)上,調(diào)用setsid()使進程成為會話組長: posix_setsid();
????????說明:當進程是會話組長時setsid()調(diào)用失敗。但第一點已經(jīng)保證進程不是會話組長。setsid()調(diào)用成功后,進程成為新的會話組長和新的進程組長,并與原來的登錄會話和進程組脫離。由于會話過程對控制終端的獨占性,進程同時與控制終端脫離。
????3. 禁止進程重新打開控制終端
??? ????現(xiàn)在,進程已經(jīng)成為無終端的會話組長。但它可以重新申請打開一個控制終端??梢酝ㄟ^使進程不再成為會話組長來禁止進程重新打開控制終端:?if($pid=pcntl_fork())?exit(0);//結(jié)束第一子進程,第二子進程繼續(xù)(第二子進程不再是會話組長)
????4. 關(guān)閉打開的文件描述符
????????進程從創(chuàng)建它的父進程那里繼承了打開的文件描述符。如不關(guān)閉,將會浪費系統(tǒng)資源,造成進程所在的文件系統(tǒng)無法卸下以及引起無法預料的錯誤。按如下方法關(guān)閉它們:
????????fclose(STDIN),fclose(STDOUT),fclose(STDERR)關(guān)閉標準輸入輸出與錯誤顯示。
????5. 改變當前工作目錄
????????進程活動時,其工作目錄所在的文件系統(tǒng)不能卸下。一般需要將工作目錄改變到根目錄。對于需要轉(zhuǎn)儲核心,寫運行日志的進程將工作目錄改變到特定目錄如chdir("/")
????6. 重設文件創(chuàng)建掩模
????????進程從創(chuàng)建它的父進程那里繼承了文件創(chuàng)建掩模。它可能修改守護進程所創(chuàng)建的文件的存取位。為防止這一點,將文件創(chuàng)建掩模清除:umask(0);
????7. 處理SIGCHLD信號
????????處理SIGCHLD信號并不是必須的。但對于某些進程,特別是服務器進程往往在請求到來時生成子進程處理請求。如果父進程不等待子進程結(jié)束,子進程將成為僵尸進程(zombie)從而占用系統(tǒng)資源。如果父進程等待子進程結(jié)束,將增加父進程的負擔,影? 響服務器進程的并發(fā)性能。在Linux下可以簡單地將SIGCHLD信號的操作設為SIG_IGN。 signal(SIGCHLD,SIG_IGN);
????????這樣,內(nèi)核在子進程結(jié)束時不會產(chǎn)生僵尸進程。這一點與BSD4不同,BSD4下必須顯式等待子進程結(jié)束才能釋放僵尸進程。關(guān)于信號的問題請參考Linux 信號說明列表

??

3、實例

<?php /**
*@author tengzhaorong@gmail.com
*@date 2013-07-25
* 后臺腳本控制類
*/
class DaemonCommand{
 
    private $info_dir="/tmp";
    private $pid_file="";
    private $terminate=false; //是否中斷
    private $workers_count=0;
    private $gc_enabled=null;
    private $workers_max=8; //最多運行8個進程
 
    public function __construct($is_sington=false,$user='nobody',$output="/dev/null"){
 
            $this->is_sington=$is_sington; //是否單例運行,單例運行會在tmp目錄下建立一個唯一的PID
            $this->user=$user;//設置運行的用戶 默認情況下nobody
            $this->output=$output; //設置輸出的地方
            $this->checkPcntl();
    }
    //檢查環(huán)境是否支持pcntl支持
    public function checkPcntl(){
        if ( ! function_exists('pcntl_signal_dispatch')) {
            // PHP _log($message);
            throw new Exception($message);
        }
        //信號處理
        pcntl_signal(SIGTERM, array(__CLASS__, "signalHandler"),false);
        pcntl_signal(SIGINT, array(__CLASS__, "signalHandler"),false);
        pcntl_signal(SIGQUIT, array(__CLASS__, "signalHandler"),false);
 
        // Enable PHP 5.3 garbage collection
        if (function_exists('gc_enable'))
        {
            gc_enable();
            $this->gc_enabled = gc_enabled();
        }
    }
 
    // daemon化程序
    public function daemonize(){
 
        global $stdin, $stdout, $stderr;
        global $argv;
 
        set_time_limit(0);
 
        // 只允許在cli下面運行
        if (php_sapi_name() != "cli"){
            die("only run in command line mode\n");
        }
 
        // 只能單例運行
        if ($this->is_sington==true){
 
            $this->pid_file = $this->info_dir . "/" .__CLASS__ . "_" . substr(basename($argv[0]), 0, -4) . ".pid";
            $this->checkPidfile();
        }
 
        umask(0); //把文件掩碼清0
 
        if (pcntl_fork() != 0){ //是父進程,父進程退出
            exit();
        }
 
        posix_setsid();//設置新會話組長,脫離終端
 
        if (pcntl_fork() != 0){ //是第一子進程,結(jié)束第一子進程   
            exit();
        }
 
        chdir("/"); //改變工作目錄
 
        $this->setUser($this->user) or die("cannot change owner");
 
        //關(guān)閉打開的文件描述符
        fclose(STDIN);
        fclose(STDOUT);
        fclose(STDERR);
 
        $stdin  = fopen($this->output, 'r');
        $stdout = fopen($this->output, 'a');
        $stderr = fopen($this->output, 'a');
 
        if ($this->is_sington==true){
            $this->createPidfile();
        }
 
    }
    //--檢測pid是否已經(jīng)存在
    public function checkPidfile(){
 
        if (!file_exists($this->pid_file)){
            return true;
        }
        $pid = file_get_contents($this->pid_file);
        $pid = intval($pid);
        if ($pid > 0 && posix_kill($pid, 0)){
            $this->_log("the daemon process is already started");
        }
        else {
            $this->_log("the daemon proces end abnormally, please check pidfile " . $this->pid_file);
        }
        exit(1);
 
    }
    //----創(chuàng)建pid
    public function createPidfile(){
 
        if (!is_dir($this->info_dir)){
            mkdir($this->info_dir);
        }
        $fp = fopen($this->pid_file, 'w') or die("cannot create pid file");
        fwrite($fp, posix_getpid());
        fclose($fp);
        $this->_log("create pid file " . $this->pid_file);
    }
 
    //設置運行的用戶
    public function setUser($name){
 
        $result = false;
        if (empty($name)){
            return true;
        }
        $user = posix_getpwnam($name);
        if ($user) {
            $uid = $user['uid'];
            $gid = $user['gid'];
            $result = posix_setuid($uid);
            posix_setgid($gid);
        }
        return $result;
 
    }
    //信號處理函數(shù)
    public function signalHandler($signo){
 
        switch($signo){
 
            //用戶自定義信號
            case SIGUSR1: //busy
            if ($this->workers_count workers_max){
                $pid = pcntl_fork();
                if ($pid > 0){
                    $this->workers_count ++;
                }
            }
            break;
            //子進程結(jié)束信號
            case SIGCHLD:
                while(($pid=pcntl_waitpid(-1, $status, WNOHANG)) > 0){
                    $this->workers_count --;
                }
            break;
            //中斷進程
            case SIGTERM:
            case SIGHUP:
            case SIGQUIT:
 
                $this->terminate = true;
            break;
            default:
            return false;
        }
 
    }
    /**
    *開始開啟進程
    *$count 準備開啟的進程數(shù)
    */
    public function start($count=1){
 
        $this->_log("daemon process is running now");
        pcntl_signal(SIGCHLD, array(__CLASS__, "signalHandler"),false); // if worker die, minus children num
        while (true) {
            if (function_exists('pcntl_signal_dispatch')){
 
                pcntl_signal_dispatch();
            }
 
            if ($this->terminate){
                break;
            }
            $pid=-1;
            if($this->workers_count0){
 
                $this->workers_count++;
 
            }elseif($pid==0){
 
                // 這個符號表示恢復系統(tǒng)對信號的默認處理
                pcntl_signal(SIGTERM, SIG_DFL);
                pcntl_signal(SIGCHLD, SIG_DFL);
                if(!empty($this->jobs)){
                    while($this->jobs['runtime']){
                        if(empty($this->jobs['argv'])){
                            call_user_func($this->jobs['function'],$this->jobs['argv']);
                        }else{
                            call_user_func($this->jobs['function']);
                        }
                        $this->jobs['runtime']--;
                        sleep(2);
                    }
                    exit();
 
                }
                return;
 
            }else{
 
                sleep(2);
            }
 
 
        }
 
        $this->mainQuit();
        exit(0);
 
    }
 
    //整個進程退出
    public function mainQuit(){
 
        if (file_exists($this->pid_file)){
            unlink($this->pid_file);
            $this->_log("delete pid file " . $this->pid_file);
        }
        $this->_log("daemon process exit now");
        posix_kill(0, SIGKILL);
        exit(0);
    }
 
    // 添加工作實例,目前只支持單個job工作
    public function setJobs($jobs=array()){
 
        if(!isset($jobs['argv'])||empty($jobs['argv'])){
 
            $jobs['argv']="";
 
        }
        if(!isset($jobs['runtime'])||empty($jobs['runtime'])){
 
            $jobs['runtime']=1;
 
        }
 
        if(!isset($jobs['function'])||empty($jobs['function'])){
 
            $this->log("你必須添加運行的函數(shù)!");
        }
 
        $this->jobs=$jobs;
 
    }
    //日志處理
    private  function _log($message){
        printf("%s\t%d\t%d\t%s\n", date("c"), posix_getpid(), posix_getppid(), $message);
    }
 
}
 
//調(diào)用方法1
$daemon=new DaemonCommand(true);
$daemon->daemonize();
$daemon->start(2);//開啟2個子進程工作
work();
 
 
 
 
//調(diào)用方法2
$daemon=new DaemonCommand(true);
$daemon->daemonize();
$daemon->addJobs(array('function'=>'work','argv'=>'','runtime'=>1000));//function 要運行的函數(shù),argv運行函數(shù)的參數(shù),runtime運行的次數(shù)
$daemon->start(2);//開啟2個子進程工作
 
//具體功能的實現(xiàn)
function work(){
      echo "測試1";
}
?>


Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to get the current session ID in PHP? How to get the current session ID in PHP? Jul 13, 2025 am 03:02 AM

The method to get the current session ID in PHP is to use the session_id() function, but you must call session_start() to successfully obtain it. 1. Call session_start() to start the session; 2. Use session_id() to read the session ID and output a string similar to abc123def456ghi789; 3. If the return is empty, check whether session_start() is missing, whether the user accesses for the first time, or whether the session is destroyed; 4. The session ID can be used for logging, security verification and cross-request communication, but security needs to be paid attention to. Make sure that the session is correctly enabled and the ID can be obtained successfully.

PHP get substring from a string PHP get substring from a string Jul 13, 2025 am 02:59 AM

To extract substrings from PHP strings, you can use the substr() function, which is syntax substr(string$string,int$start,?int$length=null), and if the length is not specified, it will be intercepted to the end; when processing multi-byte characters such as Chinese, you should use the mb_substr() function to avoid garbled code; if you need to intercept the string according to a specific separator, you can use exploit() or combine strpos() and substr() to implement it, such as extracting file name extensions or domain names.

How do you perform unit testing for php code? How do you perform unit testing for php code? Jul 13, 2025 am 02:54 AM

UnittestinginPHPinvolvesverifyingindividualcodeunitslikefunctionsormethodstocatchbugsearlyandensurereliablerefactoring.1)SetupPHPUnitviaComposer,createatestdirectory,andconfigureautoloadandphpunit.xml.2)Writetestcasesfollowingthearrange-act-assertpat

How to split a string into an array in PHP How to split a string into an array in PHP Jul 13, 2025 am 02:59 AM

In PHP, the most common method is to split the string into an array using the exploit() function. This function divides the string into multiple parts through the specified delimiter and returns an array. The syntax is exploit(separator, string, limit), where separator is the separator, string is the original string, and limit is an optional parameter to control the maximum number of segments. For example $str="apple,banana,orange";$arr=explode(",",$str); The result is ["apple","bana

JavaScript Data Types: Primitive vs Reference JavaScript Data Types: Primitive vs Reference Jul 13, 2025 am 02:43 AM

JavaScript data types are divided into primitive types and reference types. Primitive types include string, number, boolean, null, undefined, and symbol. The values are immutable and copies are copied when assigning values, so they do not affect each other; reference types such as objects, arrays and functions store memory addresses, and variables pointing to the same object will affect each other. Typeof and instanceof can be used to determine types, but pay attention to the historical issues of typeofnull. Understanding these two types of differences can help write more stable and reliable code.

Using std::chrono in C Using std::chrono in C Jul 15, 2025 am 01:30 AM

std::chrono is used in C to process time, including obtaining the current time, measuring execution time, operation time point and duration, and formatting analysis time. 1. Use std::chrono::system_clock::now() to obtain the current time, which can be converted into a readable string, but the system clock may not be monotonous; 2. Use std::chrono::steady_clock to measure the execution time to ensure monotony, and convert it into milliseconds, seconds and other units through duration_cast; 3. Time point (time_point) and duration (duration) can be interoperable, but attention should be paid to unit compatibility and clock epoch (epoch)

How does PHP handle Environment Variables? How does PHP handle Environment Variables? Jul 14, 2025 am 03:01 AM

ToaccessenvironmentvariablesinPHP,usegetenv()orthe$_ENVsuperglobal.1.getenv('VAR_NAME')retrievesaspecificvariable.2.$_ENV['VAR_NAME']accessesvariablesifvariables_orderinphp.iniincludes"E".SetvariablesviaCLIwithVAR=valuephpscript.php,inApach

How to pass a session variable to another page in PHP? How to pass a session variable to another page in PHP? Jul 13, 2025 am 02:39 AM

In PHP, to pass a session variable to another page, the key is to start the session correctly and use the same $_SESSION key name. 1. Before using session variables for each page, it must be called session_start() and placed in the front of the script; 2. Set session variables such as $_SESSION['username']='JohnDoe' on the first page; 3. After calling session_start() on another page, access the variables through the same key name; 4. Make sure that session_start() is called on each page, avoid outputting content in advance, and check that the session storage path on the server is writable; 5. Use ses

See all articles