守護進程是 Linux 服務器編程的基石(如 httpd、sshd、crond)。本文系統講解守護進程七大核心特性,提供完整可生產使用的 C 代碼實現,並演示 syslog 日誌配置與運行驗證全流程。
fork() 產生子進程,父進程退出 → 子進程脫離終端控制setsid() 創建新會話 → 成為會話組長、進程組長、脫離控制終端fork(),父進程退出 → 非會話組長,無法重新獲取控制終端NOFILE 所有繼承描述符 → 釋放資源、避免文件系統卸載失敗chdir("/") → 防止掛載文件系統無法卸載umask(0) → 確保創建文件權限不受限制signal(SIGCHLD, SIG_IGN) → 避免子進程變殭屍進程佔用資源#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <time.h>
#include <syslog.h>
#include <stdio.h>
int init_daemon(void) {
int pid, i;
// 1. 忽略終端相關信號
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGHUP, SIG_IGN);
// 2. 第一次 fork,父進程退出
pid = fork();
if (pid > 0) exit(0);
if (pid < 0) return -1;
// 3. 創建新會話,脫離控制終端
setsid();
// 4. 第二次 fork,確保非會話組長,禁止重開終端
pid = fork();
if (pid > 0) exit(0);
if (pid < 0) return -1;
// 5. 關閉所有繼承的文件描述符
for (i = 0; i < NOFILE; close(i++)) ;
// 6. 切換工作目錄到根目錄
chdir("/");
// 7. 重置文件創建掩碼
umask(0);
// 8. 忽略 SIGCHLD,防止殭屍進程
signal(SIGCHLD, SIG_IGN);
return 0;
}
int main(void) {
time_t now;
init_daemon();
// 使用 syslog 記錄日誌
openlog("TestDaemon", LOG_PID, LOG_USER);
syslog(LOG_INFO, "Test daemon started");
while (1) {
sleep(8);
time(&now);
syslog(LOG_INFO, "System time: %s", ctime(&now));
}
closelog();
return 0;
}
/etc/syslog.conf(或 rsyslog.conf)# 在文件末尾添加
user.* /var/log/test.log
/etc/init.d/syslog stop
/etc/init.d/syslog start
# 或 systemd 系統
systemctl restart rsyslog
$ ps -ef | grep test_daemon
root 12345 1 0 14:30 ? 00:00:00 ./test_daemon

?(無控制終端)S 或 Ss(會話組長)
$ tail -f /var/log/test.log
Jun 18 14:30:01 localhost TestDaemon[12345]: Test daemon started
Jun 18 14:30:09 localhost TestDaemon[12345]: System time: Tue Jun 18 14:30:09 2013
Jun 18 14:30:17 localhost TestDaemon[12345]: System time: Tue Jun 18 14:30:17 2013
daemon(3) 库函數:BSD 擴展,一行代碼完成上述大部分工作(但不可移植)systemd 管理守護進程,無需雙重 fork、setsid,直接編寫 .service 文件sigaction() 替代 signal(),設置 SA_RESTART、SA_NOCLDWAITclosefrom() (BSD) 或 /proc/self/fd 遍歷關閉#include <systemd/sd-daemon.h> // systemd 通知支持
int main() {
// 1. 初始化:解析配置、打開日誌、創建監聽套接字等
// 2. 通知 systemd 就緒
sd_notify(0, "READY=1");
// 3. 主事件循環
while (running) {
// 處理請求、定時任務等
sd_notify(0, "WATCHDOG=1"); // 看門狗心跳
}
// 4. 清理資源
return 0;
}
本文出自 “_Liang_Happy_Life__Dream” 博客,轉載請保留出處:原文鏈接