守護進程

  • 什麼是守護進程??
    守護進程(也稱精靈進程)是一類在後臺運行的特殊進程,用於執行特定的系統任務。很多守護進程在系統引導的時候啓動,並且一直運行直到系統關閉。另一些只在需要的時候才啓動,完成任務後就自動結束。守護進程通常採用以d結尾的名字,表示Daemon,如:crond(設置定時任務),httpd。
    一個守護進程的父進程是init進程,因爲它真正的父進程在fork出子進程後就先於子進程exit退出了,所以它是一個由init繼承的孤兒進程,並且都自成進程組,自成會話。
    守護進程是非交互式程序,沒有控制終端,所以任何輸出,無論是向標準輸出設備stdout還是標準出錯設備stderr的輸出都需要特殊處理。

  • 守護進程及其特性:
    (1)守護進程最重要的特性是後臺運行。在這一點上DOS下的常駐內存程序TSR與之相似。
    (2)其次,守護進程必須與其運行前的環境隔離開來。這些環境包括未關閉的文件描述符,控制終端。 會話和進程組,工作目錄以及文件創建掩模等。這些環境通常是守護進程從執行它的父進程(特別是shell)中繼承下來的。
    (3)最後,守護進程的啓動方式有其特殊之處。它可以在Linux系統啓動時從啓動腳本/etc/rc.d中啓動,可以由作業規劃進程crond啓動,還可以由用戶終端(通常是 shell)執行。總之,除開這些特殊性以外,守護進程與普通進程基本上沒有什麼區別。

  • 創建守護進程:
    首先介紹幾個創建守護進程要用到的函數
    setsid函數

頭文件:#include<unistd.h>
函數原型:pid_t setsid(void);
功能:創建一個新的Session,併成爲Session Leader
返回值:調用成功時返回新創建的Session的id,出錯返回-1

注:

調用此函數前,當前進程不允許是進程組的Leader,否則返回-1。
保證當前進程不是進程組Leader的方法:
fork()創建一個子進程,子進程父進程在一個進程組中,父進程爲該進程組的第一個進程,即爲該進程組的Leader,所以在子進程中調用setsid就不會出現問題了。

damon函數

頭文件:#include<untisd.h>
函數原型:int daemon(int nochdir, int noclose);
函數功能:創建一個守護進程
參數:
nochdir:= 0將當前目錄更改至“/”(是否改變,爲0做,爲1不做)
noclose:= 0將標準輸入、標準輸出、標準錯誤重定向至“/dev/null”(是否關閉,爲0做,爲1不做)
返回值:成功返回0,失敗返回-1
  • 守護進程的編程要點:
    (1)在後臺運行
    (2)脫離控制終端,登錄會話和進程組
    (3)禁止進程重新打開控制終端
    (4)關閉打開的文件描述符
    (5)改變當前工作目錄
    (6)重設文件創建掩模
    (7)處理SIGCHLD信號

  • 創建守護進程的一般步驟步驟:
    (1)調用umask函數,設置進程的umask爲0;
    (2)在父進程中執行fork並exit推出;
    (3)在子進程中調用setsid函數創建新的會話;
    (4)在子進程中調用chdir函數,讓根目錄 ”/” 成爲子進程的工作目錄;
    (5)在子進程中關閉任何不需要的文件描述符;

具體代碼如下:

#include <stdio.h>
#include<unistd.h>
#include<signal.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/stat.h>
void mydaemon(void)
{
    int i;
    int fd0;
    //調用fork,創建子進程,父進程退出(保證調用setsid的進程不是進程組的Leader)
    pid_t pid = fork();
    struct sigaction sa;

    umask(0);//調用umask將文件模式創建屏蔽字設置爲0
    if(pid < 0)
    {
        perror("fork");
    }
    else if(pid > 0)
    {
        //father退出
        exit(0);
    }
    else
    {
        //child
        setsid();//調用setsid創建一個新會話
        sa.sa_handler = SIG_IGN;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = 0;
        if(sigaction(SIGCHLD,&sa,NULL) < 0)
        {
            return;
        }
        if(chdir("/") < 0)
        {
            //將當前工作目錄更改爲根目錄
            printf("child dir error!\n");
            return;
        }
        //關閉不再需要的文件描述符,或者重定向到/dev/null
        close(0);
        fd0 = open("/dev/null",O_RDWR);
        dup2(fd0,1);
        dup2(fd0,2);
    }
}
int main()
{
    mydaemon();
    while(1)
    {
        sleep(1);
    }
    return 0;
}
  • 實驗結果驗證:
    關閉當前終端, 打開另外一個終端時,在命令行輸入:
ps axj | grep daemon | grep -v grep

會發現原來的會話還存在, 於是我們可以得出結論
守護進程單獨成組, 單獨成回話, 不受控制終端控制

  • 由於在Linux中,每一個系統與用戶進行交流的界面稱爲終端,每一個從此終端開始運行的進程都會依附於這個終端,這個終端就稱爲這些進程的控制終端,當控制終端被關閉時,相應的進程都會自動關閉。但是守護進程卻能夠突破這種限制,它從被執行開始運轉,直到整個系統關閉時才退出。如果想讓某個進程不因爲用戶或終端或其它變化而受到影響,那麼就把這個進程變成一個守護進程。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章