个人技术分享


0.预备知识

  • **前台进程:**和终端关联的进程
  • 任何一次会话,只允许有一个前台进程和多个后台进程
  • 守护进程不能直接向显示器打印消息,一旦打印,会被暂停、终止

1.守护进程概念

  • 守护进程也叫做精灵进程,是特殊的孤儿进程
  • 它不但运行在后台,最主要的是脱离了与终端和登录会话的所有联系
    • 也就是默默的运行在后台不想受到任何影响
  • 守护进程是非常有用的进程,在Linux当中大多数服务器用的就是守护进程,比如Web服务器http等
    • 一般对外提供服务的服务器,都是以守护进程的方式工作的,一旦启动之后,除非用户主动关闭,否则,一直会在运行

2.进程组概念

  • 进程除了有自己的PID、PPID,还有一个PGID(组ID)
  • 进程组是由一个进程或者多个进程组成,通常它们与同一作业相关联,可以收到同一终端的信号
  • 每个进程组有一个进程组组长组长一般是第一个进程
  • 如何判断一个进程是不是这个进程组的组长?
    • 进程组ID = 进程ID --> 此进程就是对应进程组组长

3.会话概念

  • 任何一次登录,登陆的用户,需要有多个进程(组)来给这个用户提供服务的,用户可以自己启动很多进程(组)
    • 把给用户提供服务的进程或者用户自己启动的所有的进程或者服务,整体都是要属于一个叫做会话的机制中的
  • 如何将自己变成自成会话呢?
    • 系统调用**setsid()**
    • **setsid()**要被成功调用,必须保证当前进程不是进程组组长
  • 如何保证自己不是组长?
    • fork()

4.守护进程化的方式

  • 系统调用daemon()
    • 原型:int daemon(int nochdir, int noclose);
    • 参数:
      • **nochdir:**若为0,则将守护进程的工作目录改为根目录,否则不做处理
      • noclose:若为0,则将守护进程的标准输入、标准输出、标准错误重定向到/dev/null,否则不做处理
  • 自己实现一个daemon()
    • 推荐使用这种,大部分服务器都是自己实现
  • nohup命令

5.实现daemon()

// 自己实现一个daemon(),让进程变为守护进程
void Daemon()
{
    // 1.忽略信号,SIGPIPE,SIGCHLD
    signal(SIGCHLD, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);

    // 2.不要让自己成为进程组组长
    if(fork() > 0)
    {
        exit(0);
    }

    // 3.调用setsid,让当前进程自成会话
    setsid();

    // 4.重定向标准输入、标准输出、标准输出
    // 守护进程不能直接向显示器打印消息
    int devnull = open("/dev/null", O_RDONLY | O_WRONLY);
    if(devnull > 0)
    {
        dup2(0, devnull);
        dup2(1, devnull);
        dup2(2, devnull);
        close(devnull);
    }
}
  • 说明:/dev/null是一个字符文件(设备),类似于Linux下的一个"文件黑洞" or"垃圾桶",通常用于屏蔽/丢弃输入输出信息