> 技术文档 > 【Linux】守护进程

【Linux】守护进程

【Linux】守护进程

目录

  • 一、预备知识
  • 二、守护进程
    • 2.1 守护进程的概念
    • 2.2 setsid函数
    • 2.3 daemon函数
  • 三、模拟实现daemon函数
  • 结尾

一、预备知识

一个进程有很多的属性,例如:进程ID、父进程ID、进程组ID、会话ID等,这里我们要讲的就是进程组ID、会话ID。

进程组是Linux操作系统中多个进程的集合,这些进程通常因为执行同一任务或共享相同目的而被组织在一起。每个进程组都有一个唯一的标识符,称为进程组ID(PGID)。当同时启动多个进程的时候,它们可以属于同一个进程组,进程组ID通常为多个进程中的第一个进程的ID。而若只有一个进程启动,则进程自成进程组,进程组ID则为进程ID。
【Linux】守护进程

会话是用户登录到系统后启动的进程集合,每个会话都有一个唯一的会话ID(SID)用于标识。每一次用户登录Linux时,操作系统会为用户提供一个shell(bash)和一个终端,给用户提供命令行解析的服务,我们称之为一个会话。在命令行中启动的所有进程,最终默认都是在当前会话中的某一个进程组中。

作业是shell(bash)用于管理和控制进程组的一个概念。当你在shell中启动一个或多个进程时,这些进程可以被视为一个作业。

【Linux】守护进程


二、守护进程

2.1 守护进程的概念

通常操作系统中进程在用户退出登录时就会退出,而我们知道服务器需要一直运行,如何让进程不受用户登录和退出的影响,就需要讲到守护进程了。

守护进程是一个独立的会话,不隶属于任何一个shell(bash)的一个会话 ,它是一种在后台运行的进程,它不与任何控制终端关联。守护进程的主要目的是执行各种系统级任务,这些任务通常不需要用户交互,并且在后台持续运行以提供服务或执行系统维护。


2.2 setsid函数

#include pid_t setsid(void);

功能:让调用setsid函数的进程成为一个新会话的会话首进程,同时也成为一个新进程组的组长进程,并且该进程会脱离原有的控制终端。

返回值

  • 成功,setsid 返回新会话的会话 ID(也就是调用进程的 PID)。
  • 失败,返回 -1,并设置 errno 以指示错误原因。

进程调用setsid函数有一个条件就是该进程不能是进程组的组长,通常我们创建子进程,退出父进程,让子进程执行后序父进程的代码,子进程就被操作系统领养,所以守护进程大部分时候都是孤儿进程


2.3 daemon函数

#include int daemon(int nochdir, int noclose);

功能:用于将当前进程转换为守护进程

参数

  • nochdir:用于控制是否改变守护进程的工作目录。
    • 如果 nochdir 为 0,守护进程会将工作目录更改为根目录 /。
    • 如果 nochdir 非 0,守护进程将保持当前工作目录不变。
  • noclose:用于控制是否关闭标准输入、输出和错误输出文件描述符。
    • 如果 noclose 为 0,守护进程会将标准输入、输出和错误输出重定向到 /dev/null,这样守护进程就不会与控制终端进行交互,避免受到终端关闭、信号等因素的影响。
    • 如果 noclose 非 0,守护进程将保持标准输入、输出和错误输出文件描述符不变。

返回值

  • 成功:返回 0,表示守护进程创建成功。
  • 失败:返回 -1,并设置相应的 errno,以指示具体的错误原因。

三、模拟实现daemon函数

#pragma once#include #include #include  #include #include const char* root = \"/\";const char* dev_null = \"/dev/null\";bool Daemon(bool nochdir, bool noclose){ // 1、忽略可能引起程序异常退出的信号 SIGCHLD SIGPIPE signal(SIGCHLD,SIG_IGN); signal(SIGPIPE,SIG_IGN); // 2、创建子进程,让父进程退出,使得子进程不成为组长 pid_t pid = fork(); if(pid > 0) exit(0); // 3、设置自己成为一个新的会画,setsid setsid(); // 4、每一个进程都有自己的CWD(当前工作路径),是否将当前进程的CWD改为根目录 // ​改为根目录以后,进程可以以绝对路径的方式找到操作系统中的文件 if(nochdir) chdir(root); // 5、变成守护进程以后,就不需要与用户的输入、输出和错误进行关联了 // ​可以将它们全部关闭,但难免服务器中会有输入、输出和错误 // ​向关闭的文件描述符中写入可能会导致进程退出 // ​所以这里将它们关闭不是最优解,而是将它们重定向到/dev/null中 // ​因为写入到/dev/null的数据会被直接丢弃,而从/dev/null读取信息,会默认读取到文件结尾 if(noclose) { int fd = open(dev_null,O_RDWR); if(fd > 0) { dup2(fd,0); dup2(fd,1); dup2(fd,2); close(fd); } } else // 不推荐 { close(0); close(1); close(2); } return true;}

结尾

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹

【Linux】守护进程