Linux中守护进程

简介: Linux中守护进程

守护进程运行在后台,不与任何控制终端相关联。在Linux中创建一个守护进程步骤如下:

一、调用fork创建一个子进程,父进程退出,子进程归到1号进程管理,子进程将作为守护进程。子进程是由父进程创建而来,因此,它不是进程组的首进程,这是接下来调用setsid的必要条件。

二、在子进程中通过setsid,创建一个会话(新创建的会话不会分配控制终端)。当前子进程将变为新会话的首进程以及新进程组的首进程。

man手册中setsid的介绍:

setsid()  creates  a new session if the calling process is not a process group leader.  
 The calling process is the leader of the new session, the process group leader of the new process group, and has no controlling terminal.  
The process group ID and session ID of the calling process are set to the PID of the calling process.  
The calling process will be the only process in this new process group  and  in  this new session.

三、调用chdir(),将当前工作目录改为根目录。因为守护进程是通过调用fork来创建,它继承来的当前工作目录可能在文件系统中的任何地方。而守护进程往往会在系统开机状态下一直运行,我们不希望这些随机目录一直处于打开状态,导致管理员无法卸载守护进程工作目录所在的文件系统。

四、关闭所有的文件描述符。我们不希望继承任何打开的文件描述符,不希望这些描述符一直处于打开状态而自己没有发现。

五、打开文件描述符0、1、2,并把它们重定向到/dev/null中。打开这些描述符的理由在于:守护进程调用的那些假设能从标准输入读或者往标准输出或标准错误写的库函数将不会因这些描述符未打开而失败。这种失败是一种隐患。要是一个守护进程未打开这些描述符,却作为服务器打开了与某个客户关联的一个套接字,那么这个套接字很可能占用这些描述符(譬如标准输出或标准错误输出的描述符1或2),这种情况下如果守护进程调用诸如perror之类函数,那就会把非预期的数据发送给那个客户。

代码实现:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/limits.h>
int main(void) {
    pid_t pid;
    pid = fork();
    if (pid == -1) 
        return -1;
    else if (pid != 0)
        exit(EXIT_SUCCESS);
    //子进程中
    if (setsid() == -1)
        return -1;
    if (chdir("/") == -1)
        return -1;
    for (int i = 0; i < NR_OPEN; i++) {
        close(i);
    }
    //重定向标准输入到 /dev/null,因为此时open返回的fd 是 0,以下同理
    open("/dev/null", O_RDONLY);
    open("/dev/null", O_RDWR);
    open("/dev/null", O_RDWR);
    return 0;
}

这时该程序便可以在后台运行了(如果是服务端程序通常都会处在一个loop中)

其实,更简单一点,我们可以直接使用daemon系统调用

#include <unistd.h>
int daemon(int nochdir, int noclose);

man手册:

The daemon() function is for programs wishing to detach themselves from the controlling terminal and run in the background as system daemons.
If nochdir is zero, daemon() changes the calling process's current working directory to the root directory ("/"); otherwise, the current working directory is left unchanged.
If noclose is zero, daemon() redirects standard input, standard output and standard error to /dev/null; otherwise, no changes are made to these file descriptors.

如果参数nochdir为0,就会将该进程的工作目录改变到根目录,如果参数noclose为0,就会将标准输入、标准输出、标准错误重定位到/dev/null。因此,两个参数一般都设置为0。

相关文章
|
11天前
|
存储 负载均衡 Linux
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(下)
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(下)
|
11天前
|
消息中间件 Unix Linux
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(上)
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(上)
|
11天前
|
缓存 Linux 调度
【Linux 系统】进程控制 -- 详解
【Linux 系统】进程控制 -- 详解
|
12天前
|
存储 缓存 Linux
【Linux】进程概念(冯诺依曼体系结构、操作系统、进程)-- 详解
【Linux】进程概念(冯诺依曼体系结构、操作系统、进程)-- 详解
|
2天前
|
Linux Shell
蓝易云 - 【Linux-Day8- 进程替换和信号】
这两个概念在Linux系统编程和shell脚本编写中都非常重要,理解它们可以帮助你更好地理解和控制Linux系统的行为。
15 9
|
3天前
|
Linux Shell
蓝易云 - 【Linux-Day8- 进程替换和信号】
这两个概念在Linux系统编程和shell脚本编写中都非常重要,理解它们可以帮助你更好地理解和控制Linux系统的行为。
5 0
|
5天前
|
算法 Linux 调度
深度解析:Linux内核的进程调度机制
【5月更文挑战第29天】 在现代操作系统中,尤其是类Unix系统如Linux中,进程调度机制是保证多任务高效运行的核心。本文将深入探讨Linux操作系统内核的进程调度器——负责管理CPU资源分配的关键组件。我们会详细分析其调度策略、调度器的演进及其在多核处理器环境下的表现。通过剖析进程调度器的工作原理和设计哲学,旨在为读者提供一个清晰的视角来理解这一复杂的系统功能。
11 0
|
11天前
|
存储 Linux 数据安全/隐私保护
Linux进程间通信
Linux进程间通信
28 6
|
11天前
|
存储 Unix Linux
【Linux 系统】进程信号 -- 详解(下)
【Linux 系统】进程信号 -- 详解(下)
|
11天前
|
NoSQL Linux Shell
【Linux 系统】进程信号 -- 详解(上)
【Linux 系统】进程信号 -- 详解(上)