C++:守护进程(附带源码)

C++ 守护进程(Daemon Process)

1. 项目实现思路

守护进程(Daemon Process)是指在后台运行的进程,通常不与终端交互,常用于处理系统任务或服务,例如日志记录、网络监听等。守护进程在系统启动时启动,并持续运行,直到系统关闭或进程被手动停止。

在类Unix系统(如Linux)中,守护进程通常会:

  • 与终端断开连接。
  • 运行在后台并脱离父进程。
  • 具有独立的进程ID(PID)。
  • 将标准输入输出重定向到文件或设备。

守护进程的创建一般包括:

  1. 创建新的会话:使进程与终端分离,成为一个新的会话的领头进程。
  2. 更改工作目录:通常将工作目录切换到/,避免守护进程占用文件系统。
  3. 重定向标准文件描述符:将stdinstdoutstderr重定向到某个日志文件。
  4. 关闭文件描述符:关闭不再需要的文件描述符。

通过以上步骤,守护进程就可以在后台正常工作。

2. 项目步骤
2.1 创建守护进程
  • 在创建守护进程时,我们首先会调用fork()创建一个子进程,然后在子进程中调用setsid()创建新的会话,从而使进程与终端分离,成为守护进程。
  • 将工作目录更改为根目录/,避免占用系统磁盘。
  • 重定向标准输入输出流(stdinstdoutstderr)到指定文件,通常会把它们指向一个日志文件。
  • 使用umask(0)确保文件权限不受影响。
2.2 守护进程任务

守护进程通常会执行一些长期运行的任务,例如监控系统资源、定期任务等。我们将在守护进程中模拟一个简单的定时任务。

3. 实现代码

以下是C++实现守护进程的基本步骤,创建一个守护进程并让它周期性地记录日志。

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

void createDaemon() {
    pid_t pid = fork();  // 创建子进程
    if (pid < 0) {
        std::cerr << "Fork failed!" << std::endl;
        exit(1);
    }

    if (pid > 0) {
        exit(0);  // 父进程退出,子进程继续运行
    }

    // 创建新的会话
    if (setsid() < 0) {
        std::cerr << "Failed to create session!" << std::endl;
        exit(1);
    }

    // 更改工作目录为根目录
    if (chdir("/") < 0) {
        std::cerr << "Failed to change directory!" << std::endl;
        exit(1);
    }

    // 关闭标准输入输出
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    // 重定向标准输出到日志文件
    std::ofstream logFile("/tmp/daemon_log.txt", std::ios::app);
    if (!logFile) {
        std::cerr << "Failed to open log file!" << std::endl;
        exit(1);
    }

    // 守护进程任务:记录时间戳到日志文件
    while (true) {
        time_t now = time(0);
        char* dt = ctime(&now);
        logFile << "Daemon running at: " << dt;
        logFile.flush();
        sleep(5);  // 每5秒记录一次
    }

    logFile.close();
}

int main() {
    createDaemon();
    return 0;
}
4. 代码解读
4.1 createDaemon() 函数
  1. 创建子进程

    • fork():创建一个子进程。如果fork()成功,它会返回两次:一次在父进程中返回子进程的PID,另一次在子进程中返回0。父进程会退出,子进程继续运行。
  2. 创建新的会话

    • setsid():调用此函数将子进程从当前终端会话中分离,成为一个新的会话的领头进程。这样,子进程就成为了一个守护进程,和父进程及终端断开了关联。
  3. 更改工作目录

    • chdir("/"):将工作目录改为根目录/,这样守护进程就不会在挂载的文件系统中占用目录(例如/tmp)。
  4. 关闭文件描述符

    • close(STDIN_FILENO)close(STDOUT_FILENO)close(STDERR_FILENO):关闭标准输入输出流,因为守护进程不需要与终端交互。
  5. 重定向标准输出到日志文件

    • 我们打开/tmp/daemon_log.txt日志文件,并将日志写入此文件中。logFile.flush()确保每次日志都会被立即写入磁盘。
  6. 守护进程任务

    • 守护进程每5秒记录一次当前的时间戳到日志文件中,模拟一个周期性的后台任务。
4.2 main() 函数
  • main()函数调用createDaemon()来创建守护进程,并开始执行任务。
5. 项目总结

这个简单的守护进程模拟了一个周期性任务,每5秒记录当前时间到日志文件。通过使用fork()setsid(),我们实现了一个脱离终端的守护进程,并通过chdir()close()确保它不依赖于终端和文件系统的状态。

守护进程的关键点:

  1. 脱离终端:通过setsid()使进程成为新的会话的领头进程,并从终端断开。
  2. 工作目录:通常将工作目录设置为根目录,以避免占用系统中的其他目录。
  3. 重定向标准输入输出:守护进程通常不会与终端交互,因此需要将stdinstdoutstderr重定向到文件或设备。
  4. 后台运行:守护进程会持续运行并执行任务,直到被显式终止。

通过这些步骤,守护进程能够在后台稳定运行,适用于需要长时间运行的服务或任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值