首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Linux 守護進程編程指南:雙 Fork 模型與關鍵步驟詳解

     編輯:關於C語言

什麼是守護進程

守護進程是運行在後台、無控制終端、獨立於用戶登錄會話的長壽命進程。典型例子:systemd、sshd、crond、nginx 主進程。

標準雙 Fork 創建流程

為確保進程完全脫離終端、不成為會話組長 (防止重新獲取控制終端),採用經典「雙 Fork」模型:


#include 
#include 
#include 
#include 

void init_daemon(void) {
    pid_t pid;
    int i;

    // 第一次 fork:父進程退出,子進程成為孤兒進程,由 init 收養
    if ((pid = fork()) > 0) exit(0);        // 父進程退出
    else if (pid < 0) exit(1);              // fork 失敗

    // 子進程:創建新會話,成為會話組長,失去控制終端
    if (setsid() < 0) exit(1);

    // 第二次 fork:確保進程不再是會話組長,無法重新打開控制終端
    if ((pid = fork()) > 0) exit(0);        // 第一子進程退出
    else if (pid < 0) exit(1);

    // 第二子進程:現在是真正的守護進程
    // 關閉所有繼承的文件描述符
    for (i = 0; i < getdtablesize(); i++) close(i);

    // 改變工作目錄到根目錄,防止掛載點無法卸載
    chdir("/");

    // 重置文件創建掩碼,獲得完整權限控制
    umask(0);

    // 可選:重定向標準輸入/輸出/錯誤到 /dev/null
    int fd = open("/dev/null", O_RDWR);
    dup2(fd, STDIN_FILENO);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    if (fd > 2) close(fd);
}

關鍵步驟解析

步驟系統調用作用
1. 脫離父進程控制fork() + 父進程 exit()Shell 認以命令已結束,繼續提示符
2. 創建新會話setsid()成為會話組長、進程組長;無控制終端
3. 防止重獲終端第二次 fork() + 第一子進程 exit()第二子進程非會話組長,無法 open("/dev/tty")
4. 關閉文件描述符close() 循環釋放繼承的打開文件,避免資源洩漏/干擾
5. 改變工作目錄chdir("/")防止當前目錄在掛載點導致磁盤無法卸載
6. 重置 umaskumask(0)確保後續創建文件權限由程式完全控制
7. 重定向標準流open("/dev/null") + dup2()防止庫函數向終端輸出導致阻塞/錯誤

現代替代方案:systemd 服務單元

現代 Linux (systemd) 推薦編寫 .service 文件,由系統管理守護化:


# /etc/systemd/system/mydaemon.service
[Unit]
Description=My Custom Daemon
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/mydaemon
Restart=on-failure
User=nobody
StandardOutput=syslog
StandardError=syslog

[Install]
WantedBy=multi-user.target

優點:自動處理守護化、日誌收集 (journald)、依賴管理、資源限制 (cgroups)、安全沙箱。

常見坑點與最佳實踐

  • 信號處理:註冊 SIGTERM 優雅退出,SIGHUP 重載配置,忽略 SIGPIPE。
  • PID 文件鎖:啟動時用 flock() 鎖定 PID 文件,防止多實例運行。
  • 日誌:使用 syslog() 或寫入固定路徑日誌文件 (配合 logrotate)。
  • 權限降級:以 root 啟動綁定特權端口後,setuid() 切換到非特權用戶運行。
  • 核心轉儲:設置 prlimit --core=unlimited 或在代碼中 setrlimit(RLIMIT_CORE, ...) 便於事後調試。

總結

雙 Fork 模型是 Unix 系統編程的經典範式,理解其每一步的「為什麼」比死記代碼更重要。現代項目優先考慮 systemd 托管,僅在極簡環境、容器內或兼容舊系統時手寫守護化邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved