守護進程

認識守護進程

守護護進程也稱精靈進程(Daemon),是運⾏在後臺的⼀種特殊進程。
獨⽴於控制終端並且週期性地執⾏某種任務或等待處理某些發⽣的事件
Linux系統啓動時會啓動很多系統服務進程,這些系統服務進程沒有控制終端,不能直接和⽤戶交互。
其它進程都是在⽤戶登錄或運⾏程序時創建,在運⾏結束或⽤戶註銷時終⽌,但系統服務進程(守護進程)不受⽤戶登錄註銷的影響,它們⼀直在運⾏着。這種進程有⼀個名稱叫守護進程(Daemon)。 

守護進程是⼀種很有⽤的進程。
  • Linux的⼤多數服務器(因爲一般服務器都需要 7*24 小時不間斷運行)就是⽤守護進程實現的。⽐如,ftp服務器,ssh服務器,Web服務器httpd等。
  • 守護進程也完成許多系統任務。⽐如,作業規劃進程crond等。

下⾯我們⽤ps axj命令查看系統中的進程。
  • 參數a表⽰不僅列當前⽤戶的進程,也列出所有其他⽤ 戶的進程
  • 參數x表⽰不僅列有控制終端的進程,也列出所有⽆控制終端的進程
  • 參數j表⽰列出與 作業控制相關的信息。

  • 凡是TPGID⼀欄寫着-1的都是沒有控制終端的進程,也就是守護進程。
  • 在COMMAND⼀列⽤[]括起來的名字表⽰內核線程,這些線程在內核⾥創建,沒有⽤戶空間代碼,因此 沒有程序⽂件名和命令⾏, 通常採⽤以k開頭的名字,表⽰Kernel。

創建守護進程


我們可以在man 手冊中查看守護進程如何創建(man 7 daemon)
  • SysV Daemons (man手冊上分爲15步,比較麻煩)
  • New-Style Daemons (新風格的守護進程,man手冊上分爲10步,也比較複雜)

一個比較簡單的創建步驟(不過也沒簡單到哪裏去...)
  1. 調用fork創建子進程,父進程終止,讓子進程在後臺繼續執行.
  2. 子進程調用setsid創建一個新的會話,並失去控制終端,調用setsid()使子進程成爲新的會話組組長和新的進程組組長,同時失去控制終端.
  3. 忽略 SIGHUP 信號,當關閉終端的時候,會話就會結束,會話結束進程組就會結束,進程組結束進程就會結束,SIGHUP信號就是負責向其他進程組發送該信號,造成其他進程終止.
  4. 忽略 SIGCHLD 信號,避免後面創建的子進程產生殭屍進程.
  5. 再次調用fork創建子子進程,子進程終止,子子進程繼續執行,由於子子進程不在是會話組的組長,從而禁止進程重新打開終端(這一步不是必須的).
  6. 吧當前的工作目錄改成根目錄,一般將工作目錄改到根目錄,這樣進程的啓動目錄也可以被卸掉.
  7. 關閉打開的文件描述符,打開一個空設備,並複製到標準輸出和標準錯誤上.避免調用一些庫函數依然向屏幕輸出信息.
  8. 重設文件創建掩碼清除從父進程那裏繼承來的文件掩碼,設爲0

代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>

void MyDaemon()
{
    // 1.創建子進程,子進程繼續執行,父進程終止
    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork");
        return;
    }
    if(pid > 0)
    {
        exit(0);
    }
    // 2.子進程調用 setsid
    setsid();
    // 3.忽略 SIGHUP信號
    signal(SIGHUP,SIG_IGN);
    // 4.忽略 SIGCHLD信號
    signal(SIGCHLD,SIG_IGN);
    // 5.修改工作目錄爲根目錄
    chdir("/");
    // 6.重定向文件描述符
    int fd = open("/dev/null",O_RDWR); //類似於垃圾桶的文件,寫入的數據直接丟棄
    if(fd < 0)
    {
        perror("fd");
        exit(1);
    }
    dup2(fd,1);
    dup2(fd,2);
    // 7.修改 umask
    umask(0);
}

int main()
{
    MyDaemon();
    while(1)
    {
        sleep(1);
    }
    return 0;
}
我麼一執行,發現當前並不是一個前臺進程
通過ps指令查看

當前TPGID這一行已經變成了 -1,證明現在的進程是守護進程.

我們可以關閉當前的終端,重啓一個終端,再次查看,mydaemon這個守護進程依舊存在.

daemon函數

上面的步驟太太太繁瑣了,C語言爲我們提供了一個daemon函數

#include <unistd.h>
int daemon(int nochdir, int noclose);

兩個參數(man 3 daemon):
    If nochdir is zero, daemon() changes the calling process's current working directory to the root  directory  ("/");  other‐wise, the current working directory is left unchanged.

    If  noclose  is  zero,  daemon()  redirects  standard input, standard output and standard error to /dev/null; otherwise, nochanges are made to these file descriptors.

代碼演示:
#include <stdio.h>
#include <unistd.h>

int main()
{
    daemon(0,0);
    while(1)
    {
        sleep(1);
    }
    return 0;
}
nohup指令

可以直接將一個進程變爲守護進程. 及其好用!!!

使用:
    nohup [要變爲守護進程的進程] &

我們發現當前的TPGID並不是-1,不要緊,我們重啓終端,再來查看

當前的 TPGID 就是-1 了
發佈了77 篇原創文章 · 獲贊 50 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章