Linux

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > Linux > Linux进程脱离父进程控制设置

Linux进程脱离父进程控制设置过程

作者:学亮编程手记

这篇文章介绍了在Linux系统中使进程完全脱离父进程控制的方法,包括使用`setsid()`、`setpgid()`等系统调用,并推荐使用systemd服务,文中还提到了一些注意事项,如双重fork技巧、信号处理和资源清理等

在Linux中,要使进程完全脱离父进程控制,通常需要使用以下系统调用组合:

1.setsid() - 创建新会话

这是最关键的一步,它会:

#include <unistd.h>
#include <stdio.h>

int main() {
    pid_t pid = fork();
    
    if (pid < 0) {
        perror("fork failed");
        return 1;
    }
    
    // 父进程退出
    if (pid > 0) {
        _exit(0);
    }
    
    // 子进程创建新会话
    if (setsid() < 0) {
        perror("setsid failed");
        return 1;
    }
    
    // 此时进程已脱离原会话和控制终端
    // 继续执行守护进程逻辑...
    
    return 0;
}

2.setpgid() - 设置进程组ID

用于更精确地控制进程组关系:

#include <unistd.h>
#include <stdio.h>

int main() {
    pid_t pid = fork();
    
    if (pid < 0) {
        perror("fork failed");
        return 1;
    }
    
    if (pid == 0) {  // 子进程
        // 将自己放入新的进程组(通常与setsid配合)
        if (setpgid(0, 0) < 0) {
            perror("setpgid failed");
            return 1;
        }
        
        // 然后创建新会话
        if (setsid() < 0) {
            perror("setsid failed");
            return 1;
        }
    } else {  // 父进程
        // 父进程可以等待子进程设置完成
        sleep(1);
        // 父进程退出,子进程被init进程接管
    }
    
    return 0;
}

3.完整的守护进程实现

#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

void daemonize() {
    pid_t pid;
    
    // 1. 创建子进程,父进程退出
    pid = fork();
    if (pid < 0) {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    
    if (pid > 0) {  // 父进程
        exit(EXIT_SUCCESS);
    }
    
    // 2. 创建新会话,脱离控制终端
    if (setsid() < 0) {
        perror("setsid");
        exit(EXIT_FAILURE);
    }
    
    // 3. 改变工作目录到根目录
    if (chdir("/") < 0) {
        perror("chdir");
        exit(EXIT_FAILURE);
    }
    
    // 4. 重设文件权限掩码
    umask(0);
    
    // 5. 关闭所有文件描述符
    for (int i = 0; i < sysconf(_SC_OPEN_MAX); i++) {
        close(i);
    }
    
    // 6. 重定向标准输入输出到/dev/null
    int fd = open("/dev/null", O_RDWR);
    if (fd != -1) {
        dup2(fd, STDIN_FILENO);
        dup2(fd, STDOUT_FILENO);
        dup2(fd, STDERR_FILENO);
        if (fd > 2) {
            close(fd);
        }
    }
}

int main() {
    daemonize();
    
    // 守护进程的主要逻辑
    while (1) {
        // 执行任务
        sleep(10);
    }
    
    return 0;
}

4.使用 systemd 服务的现代方法

对于现代Linux系统,推荐使用systemd服务:

# /etc/systemd/system/my-service.service
[Unit]
Description=My Daemon Service
After=network.target

[Service]
Type=forking
PIDFile=/var/run/my-service.pid
ExecStart=/usr/local/bin/my-daemon
Restart=always
User=nobody
Group=nogroup

# 确保进程完全独立
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=true
PrivateDevices=yes

[Install]
WantedBy=multi-user.target

5.关键区别

系统调用作用效果
setsid()创建新会话进程成为会话首进程,脱离控制终端
setpgid(pid, pgid)设置进程组将指定进程放入指定进程组
fork() + setsid()标准守护进程完全脱离父进程控制

6.注意事项

这样设置的进程将完全独立于原始父进程,即使父进程退出也不会影响它,并由init/systemd进程接管。

7.总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文