在 Linux 中,守护进程(Daemon)是一种在后台运行、不与终端关联的进程。创建守护进程有一套经典流程,下面从原理和示例代码两方面说明。
init(或 systemd)/fork() 脱离终端fork() 一次,父进程退出setsid() 创建新会话fork() 第二次(可选,避免重新获得终端)chdir("/")umask(0)#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void create_daemon(void)
{
pid_t pid;
// 1. fork,父进程退出
pid = fork();
if (pid < 0) exit(1);
if (pid > 0) exit(0);
// 2. 创建新会话
if (setsid() < 0) exit(1);
// 3. 再 fork 一次(可选)
pid = fork();
if (pid < 0) exit(1);
if (pid > 0) exit(0);
// 4. 改变工作目录
chdir("/");
// 5. 重设文件权限掩码
umask(0);
// 6. 关闭标准输入输出
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 重定向到 /dev/null
open("/dev/null", O_RDONLY); // stdin
open("/dev/null", O_WRONLY); // stdout
open("/dev/null", O_WRONLY); // stderr
}
int main(void)
{
create_daemon();
// 守护进程主体
while (1) {
sleep(10);
}
return 0;
}
fork()?| fork 次数 | 作用 |
|---|---|
| 第一次 | 脱离父进程和终端 |
setsid() |
成为会话首进程 |
| 第二次 | 防止重新打开控制终端 |
第二次 fork 不是必须的,但更安全。
现在不推荐手写守护进程,而是由 systemd 管理。
[Unit]
Description=My Daemon
[Service]
ExecStart=/usr/local/bin/mydaemon
Restart=always
[Install]
WantedBy=multi-user.target
然后:
systemctl daemon-reload
systemctl start mydaemon
systemctl enable mydaemon
✅ systemd 自动完成:
printf(stderr, ...)syslog 或 /var/logkill(pid, SIGTERM) 控制退出| 场景 | 建议 |
|---|---|
| 学习 / 面试 | 手写 fork + setsid |
| 生产环境 | 使用 systemd |
| 简单后台 | nohup ./app & |
如果你需要 Python / Shell / systemd 实战示例,或想了解 如何优雅退出守护进程,可以继续问我。