守护进程(linux)

目录

1.守护进程

一、核心目标

二、代码逐段解析

[1. 头文件与常量定义](#1. 头文件与常量定义)

[2. Daemon 函数核心逻辑](#2. Daemon 函数核心逻辑)

[步骤 1:忽略可能导致异常退出的信号](#步骤 1:忽略可能导致异常退出的信号)

[步骤 2:让父进程退出,子进程成为 "孤儿进程"](#步骤 2:让父进程退出,子进程成为 "孤儿进程")

[步骤 3:创建新会话,脱离控制终端](#步骤 3:创建新会话,脱离控制终端)

[步骤 4:切换工作目录(可选)](#步骤 4:切换工作目录(可选))

[步骤 5:处理标准 I/O 描述符(关闭或重定向)](#步骤 5:处理标准 I/O 描述符(关闭或重定向))

三、使用场景

四、总结


1.守护进程

Daemon.hpp

cpp 复制代码
C++
#pragma once
#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
const char *root = "/";
const char *dev_null = "/dev/null";
void Daemon(bool ischdir, bool isclose)
{
// 1. 忽略可能引起程序异常退出的信号
signal(SIGCHLD, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
// 2. 让自己不要成为组长
if (fork() > 0)
exit(0);
// 3. 设置让自己成为一个新的会话, 后面的代码其实是子进程在走
setsid();
// 4. 每一个进程都有自己的 CWD,是否将当前进程的 CWD 更改成为 /根目录
if (ischdir)
chdir(root);
// 5. 已经变成守护进程啦,不需要和用户的输入输出,错误进行关联了
if (isclose)
{
close(0);
close(1);
close(2);
}
else
{
// 这里一般建议就用这种
int fd = open(dev_null, O_RDWR);
if (fd > 0)
{
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
close(fd);
}
}
}

这段代码是一个典型的守护进程(Daemon)初始化函数,用于将一个普通进程转换为守护进程。守护进程是在后台长期运行、脱离控制终端、独立于用户交互的进程(如系统服务、后台任务等)。下面逐部分解析其实现逻辑和作用:

一、核心目标

将调用该函数的进程转换为守护进程,使其具备以下特性:

  • 脱离控制终端(不接收终端输入 / 输出,不受终端关闭影响);
  • 在后台独立运行,不阻塞用户交互;
  • 避免成为 "僵尸进程",长期稳定运行。

二、代码逐段解析

1. 头文件与常量定义

cpp

运行

复制代码
#pragma once  // 防止头文件重复包含(类似#ifndef的简化写法)
#include <iostream>
#include <cstdlib>   // 包含exit()等函数
#include <signal.h>  // 信号处理(signal())
#include <unistd.h>  // 包含fork()、chdir()、setsid()等系统调用
#include <fcntl.h>   // 文件操作(open()、dup2()等)
#include <sys/types.h>
#include <sys/stat.h>

const char *root = "/";         // 根目录路径(用于切换工作目录)
const char *dev_null = "/dev/null";  // 空设备路径(用于重定向I/O)

这些头文件提供了进程控制、信号处理、文件操作等核心系统调用的声明,常量用于后续路径操作。

2. Daemon 函数核心逻辑

函数参数 ischdir 控制是否切换工作目录,isclose 控制是否直接关闭标准 I/O 描述符(或重定向到空设备)。

步骤 1:忽略可能导致异常退出的信号

cpp

运行

复制代码
signal(SIGCHLD, SIG_IGN);  // 忽略子进程结束信号(防止僵尸进程)
signal(SIGPIPE, SIG_IGN);  // 忽略管道破裂信号(避免向已关闭管道写数据时崩溃)
  • SIGCHLD:子进程退出时会向父进程发送此信号,若忽略,内核会自动回收子进程资源,避免产生僵尸进程。
  • SIGPIPE:当向一个已关闭的管道(或 socket)写入数据时产生,忽略可防止程序因该信号异常退出。
步骤 2:让父进程退出,子进程成为 "孤儿进程"

cpp

运行

复制代码
if (fork() > 0)  // 父进程分支
    exit(0);     // 父进程退出,仅保留子进程
  • fork() 创建子进程后,父进程立即退出,子进程会被操作系统的 init 进程(或 systemd 等进程管理器)收养,避免受原父进程退出的影响。
  • 更重要的是:此时子进程不是进程组组长 (进程组组长是原父进程,已退出),为下一步 setsid() 做准备(setsid() 要求调用进程不能是进程组组长,否则失败)。
步骤 3:创建新会话,脱离控制终端

cpp

运行

复制代码
setsid();  // 子进程创建新会话,成为新会话的首进程

setsid() 的作用是:

  • 子进程脱离原有的进程组和会话;
  • 成为新会话的首进程和新进程组的组长;
  • 最重要:脱离控制终端 (不再与原终端关联,不会收到终端的信号如 Ctrl+C 产生的 SIGINT)。
步骤 4:切换工作目录(可选)

cpp

运行

复制代码
if (ischdir)
    chdir(root);  // 若需要,将工作目录切换到根目录 "/"
  • 守护进程通常长期运行,若原工作目录被卸载(如挂载的外部设备),会导致进程异常。切换到根目录(/,几乎不会被卸载)可避免此问题。
步骤 5:处理标准 I/O 描述符(关闭或重定向)

cpp

运行

复制代码
if (isclose) {
    // 直接关闭标准输入(0)、输出(1)、错误(2)
    close(0);
    close(1);
    close(2);
} else {
    // 更常用:重定向到/dev/null(空设备,写入的数据会被丢弃)
    int fd = open(dev_null, O_RDWR);  // 打开空设备(可读可写)
    if (fd > 0) {
        dup2(fd, 0);  // 标准输入重定向到/dev/null(读不到数据)
        dup2(fd, 1);  // 标准输出重定向到/dev/null(输出被丢弃)
        dup2(fd, 2);  // 标准错误重定向到/dev/null
        close(fd);    // 关闭原始fd,避免资源泄漏
    }
}
  • 守护进程无需与用户交互,保留标准 I/O(关联原终端)没有意义,甚至可能因终端关闭导致 I/O 错误。
  • 直接关闭描述符(isclose=true)或重定向到 /dev/nullisclose=false)是标准做法。/dev/null 被称为 "黑洞",所有写入的数据会被丢弃,读取时直接返回 EOF,避免 I/O 阻塞。

三、使用场景

调用 Daemon(true, false) 后,当前进程就会变成一个标准的守护进程,例如:

cpp

运行

复制代码
int main() {
    Daemon(true, false);  // 转换为守护进程
    // 后续逻辑:如循环处理任务、监听端口等(长期运行)
    while (true) {
        sleep(1);  // 模拟工作
    }
    return 0;
}

四、总结

这段代码通过信号忽略、进程分叉、创建新会话、切换工作目录、重定向 I/O五个核心步骤,将普通进程转换为守护进程,使其具备后台运行、脱离终端、稳定持久的特性,是 Linux 后台服务开发的基础工具函数。

相关推荐
Leinwin11 小时前
微软与Anthropic深化战略合作,在Azure Foundry平台部署Claude系列AI模型
人工智能·microsoft·azure
JasonSJX2 天前
海海软件成为微软 PlayReady DRM 官方合作伙伴
microsoft·drm·视频加密·playready·数字版权保护
西焱4402 天前
微软官方直链下载(winxp,win8,win10,win11镜像下载)
microsoft
季春二九2 天前
微软 .Net 运行库丨多语言丨离线全集丨静默安装丨多架构支持
microsoft·.net
Elastic 中国社区官方博客2 天前
Elasticsearch:Microsoft Azure AI Foundry Agent Service 中用于提供可靠信息和编排的上下文引擎
大数据·人工智能·elasticsearch·microsoft·搜索引擎·全文检索·azure
初九之潜龙勿用2 天前
C# 使用豆包 AI 模型实现首尾帧模式的视频生成
人工智能·microsoft·c#·ai编程·视频·ai模型·豆包
WangMing_X3 天前
C# XML操作演示示例项目(附源码完整)
开发语言·microsoft·php
努力的光头强3 天前
《智能体设计模式》从零基础入门到精通,看这一篇就够了!
大数据·人工智能·深度学习·microsoft·机器学习·设计模式·ai
Splashtop高性能远程控制软件3 天前
行业观察 | 微软修复63个漏洞,包含零日与CVSS 9.8关键漏洞
运维·安全·microsoft·自动化·远程桌面·splashtop