3.7、守护进程详解、范例演示

2019-04-01  本文已影响0人  奥斯特洛司机

1、普通进程运行观察
进程有对应的终端,终端退出,那么该进程也就消失了。父进程是bash。
终端被占用。
2、守护进程基本概念
守护进程是一种长期运行的进程,在后台运行,不跟任何终端关联。
基本特点:生存周期比较长,一般是操作系统启动的时候启动,
操作系统关闭的时候才关闭。
守护进程跟终端无关联,没有控制终端。不随终端退出而退出。
守护进程在后台运行。
linux操作系统本身有很多守护进程在默默运行,维持着系统的日常活动,30-50个。
ppid = 0的属于内核进程,跟随系统启动而启动,生命周期贯穿整个系统。
比如:init,kthreadd
cmd列名字带【】的就是内核守护进程。
init:也是系统守护进程,负责启动各运行层次特定的系统服务。
所以很多进程的ppid是init。。也负责收养孤儿进程。
cmd列中不带【】的是普通守护进程(用户守护进程)
共同点总结:大多数守护进程都是以超级用户权限运行的;
守护进程没有控制终端,TT这列显示?
a、内核守护进程以无控制终端方式启动
b、普通守护进程可能是守护进程调用了setsid的结果(无控制终端)。

  守护进程虽然可以从终端启动,但和终端不挂钩。守护进程实在后台爱运行,不应该从键盘上接收任何东西。也不应该把输出结果打印大终端上来。所以要把守护进程的标准输入、标准输出重定向到空设备。

3、守护进程编写规则
a、调用umask(0):用来限制(屏蔽)一些文件权限的。
b、fork一个子进程出来,然后父进程退出,把控制终端空出来,
fork的目的是想成功调用setsid()来建立新会话。
目的是让子进程有单独的sid,而且子进程也成为新进程组的组长进程,
同时不关联任何终端了。
c、把守护进程的标准输入、标准输出重定向到空设备。从而确保不从键盘接收,
不打印到屏幕。
int fd;
fd = open("/dev/null" ,O_RDWR);
dup2(fd, STDIN_FILENO); //复制文件描述符,类似指针赋值,
标准输入指向黑洞。
dup2(fd, STDOUT_FILENO);
if(fd > STDERR_FILENO)
close(fd); //等价于fd = NULL
3.1、文件描述符
正数,用来标识一个文件。当你打开一个存在的文件,
或者创建一个新文件,操作系统都会返回这个文件描述符。
后续对文件操作的一些函数,都会调用到这个文件描述符作为参数。

          三个特殊的文件描述符:0(标准输入),1(标准输出),2(标准出错)
          分别对应的符号常量:STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO
          类Unix默认从STDIN_FILENO读数据,从STDOUT_FILENO写数据。
          一切皆文件。所以以上都看成文件。
          程序启动,自动打开。
   3.2、输入输出重定向
           输出重定向:1>/dev/null
   3.3、空设备
            /dev/null,是一个特殊的设备文件,丢弃写入。
   3.4、实现范例,nginx提炼出来可用于商业用途
|#include  <sys/stat.h>
|#include <fcntl.h>

//创建守护进程
int ngx_daemon()
{
     int fd;
     switch(fork())
     {
          case -1:
                      //创建子进程失败,这里可以写日志。。。。
                      return -1;
          case 0:
                      //子进程,走到这里,直接break
                      break;
         default:
                     //父进程,直接退出
                     exit(0);
     }
     //只有子进程流程才能走到这里
     if(setsid() == -1){    //脱离终端,终端关闭,将跟此子进程无关
         //记录错误日志
          return -1;
     }
     umask(0); //设置为0,不要让它来限制文件权限,以免引起混乱

     fd = open("/dev/null", O_RDWR); //打开黑洞设备,以读写方式打开
     if(fd == -1){
         //记录错误日志
         return -1;
     }
     if(dup2(fd, STDIN_FILENO) == -1){ //先关闭STDIN_FILENO,
                                                              //改变指向之前,先close
          //记录错误日志
          return -1;
     }
     if(dup2(fd, STDOUT_FILENO) == -1){   //输出重定向到/dev/null
          //记录错误日志
          return -1;
     }
     if(fd > STDERR_FILENO){
          if(close(fd) == -1)
              //记录错误日志
              return -1;
     }
     return 1;
}

int main(int argc, char* const *argv){
    if(ngx_daemon() != 1){
         //创建守护进程失败,此处写失败日志等。
         return -1;
    }
    else{
        //创建守护进程成功,执行守护进程中要干的活
        for(;;){
            sleep(1);
            printf("休息1秒,进程id = %d\n", getpid()); //此处打印无效果,标准输出已重定向到/dev/null
        }
    }
    return 0;
}

Ss :小s表示进程leader
nginx的master进程也是守护进程,这个进程就是抄自nginx。
守护进程可以用命令启动,如果想开机启动,要系统初始化脚本启动。

4、守护进程不会收到的信号
4.1、SIGHUP信号
守护进程不会受到来自内核发送的信号。
另外的进程可以发SIGHUP信号,
作为通知信号,表示配置文件已经发生改动,守护进程应该重新读入。
sudo ./nginx -s reload 给已经启动的老master发送SIGHUP信号,
使用新配置启动新worker进程
跟kill -1 pid效果一样。 (看nginx源码)
4.2、SIGINT、SIGWINCH信号(来自内核发送的)
Ctrl+C,SIGWINCH(终端窗口大小改变信号)
具体用来干嘛?

5、守护进程和后台进程的区别
守护进程和终端无挂钩,但是后台进程是挂钩的,能往终端输出东西。
守护进程关闭终端不受影响,后台进程就会跟着退出。
脱离终端,不会屏蔽文件权限。

上一篇 下一篇

猜你喜欢

热点阅读