导读:本期聚焦于小伙伴创作的《Linux守护进程实例代码分析:如何编写稳定的后台服务程序》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Linux守护进程实例代码分析:如何编写稳定的后台服务程序》有用,将其分享出去将是对创作者最好的鼓励。

Linux守护进程是独立于终端运行的后台进程,不会受到用户登录注销的影响,广泛服务于系统级功能如日志服务、定时任务等场景。编写符合规范的守护进程需要遵循特定的流程,避免进程异常退出或资源占用问题。

Linux守护进程实例代码分析:如何编写稳定的后台服务程序

守护进程的核心特性

守护进程和普通进程相比有三个核心区别,这些特性决定了它的实现逻辑:

  • 脱离终端控制,不会收到终端发出的信号如SIGINT
  • 会话和进程组独立,不会成为其他进程组的成员
  • 工作目录通常设置为根目录,避免挂载点无法卸载

标准守护进程实现步骤

按照POSIX标准,创建守护进程需要依次完成以下步骤:

  1. 调用fork创建子进程,父进程退出,让子进程成为孤儿进程被init收养
  2. 调用setsid创建新会话,让子进程成为会话首进程,脱离原终端
  3. 再次调用fork并让父进程退出,避免进程重新获得控制终端
  4. 将当前工作目录切换为根目录/
  5. 重设文件权限掩码,避免继承的掩码影响文件创建
  6. 关闭标准输入、输出、错误流,重定向到/dev/null或日志文件

完整实例代码分析

以下是一个符合规范的守护进程实例,实现了一个每10秒向日志文件写入时间戳的后台服务:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <signal.h>

// 日志文件路径
#define LOG_FILE "/tmp/daemon_demo.log"

// 信号处理函数,处理SIGTERM退出信号
void signal_handler(int sig) {
    if (sig == SIGTERM) {
        // 打开日志文件追加退出信息
        int fd = open(LOG_FILE, O_WRONLY | O_CREAT | O_APPEND, 0644);
        if (fd != -1) {
            time_t now = time(NULL);
            char buf[128];
            snprintf(buf, sizeof(buf), "守护进程收到退出信号,退出时间:%s", ctime(&now));
            write(fd, buf, strlen(buf));
            close(fd);
        }
        exit(0);
    }
}

int main() {
    pid_t pid;
    int fd;
    time_t now;
    char time_buf[128];

    // 第一步:第一次fork,父进程退出
    pid = fork();
    if (pid < 0) {
        perror("fork failed");
        exit(1);
    }
    if (pid > 0) {
        // 父进程退出,子进程成为孤儿进程
        exit(0);
    }

    // 第二步:创建新会话,脱离终端
    if (setsid() < 0) {
        perror("setsid failed");
        exit(1);
    }

    // 第三步:第二次fork,避免重新获得控制终端
    pid = fork();
    if (pid < 0) {
        perror("second fork failed");
        exit(1);
    }
    if (pid > 0) {
        exit(0);
    }

    // 第四步:切换工作目录到根目录
    if (chdir("/") < 0) {
        perror("chdir failed");
        exit(1);
    }

    // 第五步:重设文件权限掩码
    umask(0);

    // 第六步:关闭标准输入、输出、错误流,重定向到/dev/null
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
    // 重定向标准输入到/dev/null
    fd = open("/dev/null", O_RDONLY);
    if (fd != STDIN_FILENO) {
        dup2(fd, STDIN_FILENO);
        close(fd);
    }
    // 重定向标准输出和错误到日志文件
    fd = open(LOG_FILE, O_WRONLY | O_CREAT | O_APPEND, 0644);
    if (fd != STDOUT_FILENO) {
        dup2(fd, STDOUT_FILENO);
        dup2(fd, STDERR_FILENO);
        close(fd);
    }

    // 注册信号处理
    signal(SIGTERM, signal_handler);

    // 守护进程核心逻辑:每10秒写入一次时间戳到日志
    while (1) {
        now = time(NULL);
        snprintf(time_buf, sizeof(time_buf), "当前守护进程运行时间:%s", ctime(&now));
        // 此时stdout已经重定向到日志文件,直接输出即可
        printf("%s", time_buf);
        fflush(stdout);
        sleep(10);
    }

    return 0;
}

代码逻辑解析

上述代码严格按照守护进程创建步骤实现:

  • 两次fork操作确保进程完全脱离终端,第一次fork后父进程退出,子进程被init进程收养;第二次fork后再次退出父进程,避免子进程成为会话首进程后重新打开控制终端。
  • setsid调用创建新会话,让进程成为新会话的首进程,同时脱离原进程组和终端。
  • 文件描述符重定向部分,先关闭标准输入、输出、错误流,再将标准输入指向/dev/null,标准输出和错误指向日志文件,避免后台运行时输出到终端导致问题。
  • 信号处理部分注册了SIGTERM的处理函数,保证进程收到终止信号时可以正常记录退出日志再退出。

编译与运行验证

编译上述代码可以使用gcc命令:

gcc -o daemon_demo daemon_demo.c

运行生成的可执行文件后,可以通过ps -ef | grep daemon_demo查看进程状态,会发现进程没有关联的终端(TTY列显示为?),父进程是init进程(PID为1)。查看/tmp/daemon_demo.log文件可以看到每隔10秒写入的时间戳信息。如果需要停止守护进程,可以使用kill -SIGTERM 进程PID命令,进程会正常退出并写入退出日志。

常见注意事项

  • 不要在守护进程中输出调试信息到标准输出,因为标准输出已经被重定向,可能导致日志混乱
  • 如果守护进程需要读取配置文件,要注意工作目录切换为根目录后,配置文件的路径需要使用绝对路径
  • 多进程或多线程的守护进程需要额外处理进程间通信和资源同步问题,避免资源竞争

Linux守护进程daemon_process后台服务进程管理修改时间:2026-07-22 10:03:36

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。