通讯架构学习-nginx-(八) 守护进程

fork执行有关的逻辑代码:注意fork子进程返回值0
    ((fork()&&fork())||fork()&&fork());  7个进程
    可以用printf("每个实际用户ID的最大进程数=%d\n", sysconf(_SC_CHILD_MAX));
fork失败的可能性:
    a) 系统中进程太多
    b) 缺省情况 最大pid :32767
    c) 每个用户都有一个允许的开启总数:printf("每个实际用户ID的最大进程数=%d\n", sysconf(_SC_CHILD_MAX));


普通进程:a)进程有对应终端,终端退出, 进程也退出
      b)终端被占住了, 你输入各种命令这个终端都没反应

守护进程:一种长期运行进程,在后台运行, 不和任何终端关联
      a)生存周期长, 操作系统启动时, 启动, 操作系统关闭时, 关闭
      b)守护进程和终端无关联, 控制终端退出 不会导致守护进程退出
      c)后台运行,不占终端
      d)linux本身有很多守护进程在运行
      ps -efj
      ppid=0的是内核进程, 跟随系统一起启动
      带中括号的都是内核守护进程 
          老祖init, 也是系统守护进程,辅助他负责启动各运行层次的系统服务
      cmd队列不带中括号的为普通守护进程,多数都是进程组组长


共同点总结:大多数守护进程都是以超级用户特权运行
        守护进程大多数没有终端
        内核守护进程以无控制终端启动
        普通守护进程可能是守护进程调用了setsid的结果(无控制终端)
守护进程编写规则:
    a)调用umask(0):是一个函数, 用来限制一些文件的权限
    b)fork()一个子进程出来, 然后父进程退出, 为了把终端空出来,干其他事
    //fork的目的是想成功调用setsid来建立新会话, 子进程有单独的sid,而且子进程也成为了一个新的进程组    //的组长, 同时,子进程不关联任何终端了。
    c)守护进程虽然可以通过终端启动, 但是不挂钩,也可以通过系统初始化脚本启动, 守护进程在后台运行,     不应该从键盘上接受东西,也不应该把东西输入到屏幕,所以要把守护进程的标准输入输出重定向到空设备。
    以下为重定向代码:dup2:复制文件描述符 像指针复制一样, 把左边给右边
    //int fd;
    //fd = open("/dev/null", 0_RDWR);
    // dup2(fd, STDIN_FILENO);
    // dup2(fd, STDOUT_FILENO);
    // if(fd>STDERR_FILENO)
    //       close(fd); //等价于fd=null
    -----------------------------------------------
一些概念:
    文件描述符:是一个正数,用来表示一个文件。当你打开一个存在的文件,操作系统都会返回一个文件描述符                     后续对这个文件的操作的一些函数, 都会用到这个文件描述符作为参数
            0:一般表示标准输入(键盘) 对于的符号位STDIN_FILENO
           1:标准输出【屏幕】 STDOUT_FILENO
           2:标准错误【屏幕】STDERR_FILENO
               类Unix操作系统默认 从STDIN_FILENO读数据,向STDOUT_FILENO写数据, 向STDERR_FILENO写错                   误
                   类Unix有个说法,一切皆文件,它把0,1,2都看成文件,即像看待文件,操作文件一样,看待                    0,1,2,操作    0,1,2
               同时,你程序一旦运行起来, 这三个文件自动打开, 0,1,2会自动打开,自动指向对应设备
               例:write(STDOUT_FILENO, "aaabbb", 6);
       输出重定向:
        输出重定向:我标准输出文件描述符不指向屏幕,例如指向(重定向)一个文件
        重定向在命令行中 用>即可
        例如:ls -la > myfileout 本该在屏幕上显示的内容被写到了myfileout里去了 

    输入重定向:一般用< 例如:cat单独使用 即输出你用键盘输入的
                  cat < myfileout 即为重定向
    综合:cat < myfilein > myoutfile
    空设备: /dev/null (也是一个文件, 设备文件):丢弃一切写入的数据

守护进程实现范例:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
#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)
    {
        //记录错误日志
        return -1;
    }
    if(dup2(fd, STDOUT_FILENO) == -1) //先关闭STDOUT_FILENO 在复制
    {
        //记录错误日志
        return -1;
    }
    if(fd > STDERR_FILENO)
    {
        if(close(fd) == -1)
        {
            //释放这个文件描述符, 不然他会一直占着资源
            return -1;
        }
    }

    return 1;
}

//创建守护进程, 成功返回1
int main()
{
   if(ngx_daemon() !=1)
   {
       //创建失败,可以写入日志
       return 1;
   }
   else
   {
       for(;;)
       {
           sleep(1);
           printf("休息一秒, 进程id=%d\n", getpid());//这里打印也没有,因为输出已经重定向
       }
   }
    return 0;
}    

守护进程不会受到的信号:内核发给你, 另外的进程发给你的
            守护进程不会收到来自内核的SIGHUP信号
            很多守护进程把这个信号作为通知信号,表示配置文件已经发生改动,守护进程应该重新读入其配置文件:sudo ./nginx -s reload

 守护进程也不会受到来自内核的SIGINT(ctrl+c), SIGWINCH(终端窗口大小改变信号)信号

守护进程和后台进程的区别:
        守护进程和终端不挂钩,后台可以输出,和终端挂钩
        守护进程关闭终端不受影响, 后台进程会退出


版权声明:本文为weixin_39278430原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。