什么是守护进程?

在 Unix/Linux 系统中,**守护进程(Daemon Process)**是一种长期运行的后台进程,通常不受终端会话控制,适用于服务类任务,如 Web 服务器、数据库管理系统等。

在《Unix 环境高级编程》中,守护进程的特点主要包括:

  • 无控制终端:独立于用户的登录会话。
  • 后台运行:通常使用 fork() 使其脱离控制终端。
  • 会话管理:使用 setsid() 创建新的会话并成为会话首进程。
  • 工作目录:通常切换到 / 避免阻止文件系统卸载。
  • 文件权限:调整 umask(0) 以确保文件权限可控。
  • 日志管理:使用 syslog 记录日志。

守护进程的创建步骤

1. 创建子进程并退出父进程

pid_t pid = fork();
if (pid < 0) {
    exit(EXIT_FAILURE);
} else if (pid > 0) {
    exit(EXIT_SUCCESS); // 让父进程退出
}

2. 创建新会话,使进程脱离控制终端

if (setsid() < 0) {
    exit(EXIT_FAILURE);
}

3. 处理信号,防止孤儿进程

signal(SIGCHLD, SIG_IGN);
signal(SIGHUP, SIG_IGN);

4. 关闭文件描述符,避免资源占用

for (int i = sysconf(_SC_OPEN_MAX); i >= 0; i--) {
    close(i);
}

5. 重定向标准输入、输出和错误到 /dev/null

open("/dev/null", O_RDWR);
dup(0);
dup(0);

完整的守护进程示例

以下是一个完整的 C++ 守护进程示例,支持日志记录和信号处理。

#include <iostream>
#include <fstream>
#include <csignal>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

void signal_handler(int signo) {
    if (signo == SIGTERM || signo == SIGINT) {
        std::ofstream log("/tmp/daemon.log", std::ios::app);
        log << "Daemon terminated" << std::endl;
        log.close();
        exit(0);
    }
}

void daemonize() {
    pid_t pid = fork();
    if (pid < 0) exit(EXIT_FAILURE);
    if (pid > 0) exit(EXIT_SUCCESS);

    umask(0);
    if (setsid() < 0) exit(EXIT_FAILURE);
    signal(SIGCHLD, SIG_IGN);
    signal(SIGHUP, SIG_IGN);
    pid = fork();
    if (pid < 0) exit(EXIT_FAILURE);
    if (pid > 0) exit(EXIT_SUCCESS);
    chdir("/");
    for (int x = sysconf(_SC_OPEN_MAX); x >= 0; x--) close(x);
    open("/dev/null", O_RDWR);
    dup(0);
    dup(0);
    signal(SIGTERM, signal_handler);
    signal(SIGINT, signal_handler);
}

int main() {
    daemonize();
    while (true) {
        std::ofstream log("/tmp/daemon.log", std::ios::app);
        log << "Daemon running..." << std::endl;
        log.close();
        sleep(10);
    }
    return 0;
}

运行与测试

编译后运行:

g++ daemon.cpp -o daemon
./daemon

查看日志输出:

tail -f /tmp/daemon.log

终止守护进程:

pkill daemon

总结

守护进程是 Unix/Linux 后台服务的基础,理解其原理有助于开发稳定可靠的系统级应用。