守护进程

一般运行在后台,并且没有控制终端,同时是一直运行,并随操作系统启动

进程启动之后,进程的内存数据会写入到 /proc目录中

编写守护进程的要求

  1. 设置文件创建屏蔽字 umask(0) umask系统屏蔽字
  2. 一般父进程先fork一个子进程,然后父进程退出,子进程调佣setsid函数创建会话,如果调用setsid的进程是组长进程就会报错
    1. 该进程会变成组长进程
    2. 该进程会变成会话首进程
    3. 该进程不再有控制终端
    4. 当调用setsid之后,一般会在创建一个子进程,让会话首进程退出,确保该进程不会再获得控制终端
  3. 把守护进程的工作目录设置为根目录
  4. 把一些文件描述符关闭,[标准输入,标准输出,标准错误]
  5. 有时候会把输出重定向到 /dev/null,一般喜欢吧 /dev/null 代替 0,1,2
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
umask(0);
$pid = pcntl_fork();

if($pid>0){
    exit(0);
}

if(-1 == posix_setsid()){
    echo 'set sid error';
}

$pid = pcntl_fork();
if($pid > 0){
    // 会话首进程退出
    exit(0);
}
// 该进程会变成组长进程,会话首进程,没有控制终端
chdir("/");
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);

// 当关闭以上标准输出后,如果后面创建文件时,文件描述符会从0开始,一般重定向到 /dev/null代替原来的0,1,2
$stdin = fopen("/dev/null", "a"); //此时$stdin文件描述符为0
$stdout = fopen("/dev/null", "a"); //此时$stdout文件描述符为1
$stderr = fopen("/dev/null", "a"); //此时$stderr文件描述符为2
//file_put_contents("/home/caoayu/test.log", posix_getpid());
$fd = fopen("/home/caoayu/test.log", 'a');
$pid = pcntl_fork();
if($pid == 0){
    fprintf($fd, "pid = %d,ppid = %d, sid = %d,time=%s\n",posix_getpid(),posix_getppid(),posix_getsid(posix_getpid()),time());
    while (true){
        sleep(3);
    }
    exit(0);
}

$pid = pcntl_wait($status);
if($pid > 0){
    fprintf($fd, "exit pid = %d,ppid = %d, sid = %d,time=%s\n",$pid,posix_getppid(),posix_getsid(posix_getpid()),time());
    fclose($fd);
    exit(0);
}

设置为守护进程后需要使用信号来暂停或结束进程