守護程式的概念和建立實驗

wzm10455發表於2013-01-16

1.關於程式的幾個理解:

前臺程式是依賴於終端而存在的,一旦終端關閉了,前臺的程式也就關閉了,而其實真正的終端並非是我們所看到的終端,可以通過ctrl+alt+f5切換(巨集基)。關閉的終端並不影響後臺程式的執行。而且,值得注意的是守護程式只有在關機的時候才會停止執行。

2.

程式組:一個或多個程式的集合

前臺程式組:一個或多個前臺程式組的集合

後臺程式組:一個或多個後臺程式的集合

程式組id:程式組長程式id,一般是指第一個程式

會話:一個或多個程式組的集合(一次使用者登陸的過程)

3

在linux或者unix作業系統中在系統的引導的時候會開啟很多服務,這些服務就叫做守護程式。為了增加靈活性,root可以選擇系統開啟的模式,這些模式叫做執行級別,每一種執行級別以一定的方式配置系統。 守護程式是脫離於終端並且在後臺執行的程式。守護程式脫離於終端是為了避免程式在執行過程中的資訊在任何終端上顯示並且程式也不會被任何終端所產生的終端資訊所打斷。

4.守護程式的建立包括六個基本過程:

  a。umask(0):重設檔案許可權掩碼

檔案許可權掩碼是指遮蔽掉檔案許可權中的對應位。比如,有個檔案許可權掩碼是050,它就遮蔽了檔案組擁有者的可讀與可執行許可權。由於使用fork函式新建的子程式繼承了父程式的檔案許可權掩碼,這就給該子程式使用檔案帶來了諸多的麻煩。因此,把檔案許可權掩碼設定為0,可以大大增強該守護程式的靈活性。設定檔案許可權掩碼的函式是umask。在這裡,通常的使用方法為umask(0)。
 b:建立子程式,父程式退出:

 if(fork()<0) exit();

在Linux中父程式先於子程式退出會造成子程式成為孤兒程式,而每當系統發現一個孤兒程式時,就會自動由1號程式(init)收養它,這樣,原先的子程式就會變成init程式的子程式。

 c:建立新會話:

 會話週期:會話期是一個或多個程式組的集合。通常,一個會話開始於使用者登入,終止於使用者退出,在此期間該使用者執行的所有程式都屬於這個會話期。

(1)setsid函式作用:
setsid函式用於建立一個新的會話,並擔任該會話組的組長。呼叫setsid有下面的3個作用:
讓程式擺脫原會話的控制
讓程式擺脫原程式組的控制
讓程式擺脫原控制終端的控制
那麼,在建立守護程式時為什麼要呼叫setsid函式呢?由於建立守護程式的第一步呼叫了fork函式來建立子程式,再將父程式退出。由於在呼叫了fork函式時,子程式全盤拷貝了父程式的會話期、程式組、控制終端等,雖然父程式退出了,但會話期、程式組、控制終端等並沒有改變,因此,這還不是真正意義上的獨立開來,而setsid函式能夠使程式完全獨立出來,從而擺脫其他程式的控制。

d:更改目錄為根目錄,防止當前目錄被解除安裝:chdir("/");

e:關閉所有檔案描述符:同檔案許可權碼一樣,用fork函式新建的子程式會從父程式那裡繼承一些已經開啟了的檔案。這些被開啟的檔案可能永遠不會被守護程式讀寫,但它們一樣消耗系統資源,而且可能導致所在的檔案系統無法卸下。

for(i=0;i<getdtablesize();i++)

{

close(i);

}

 f:int fd0,fd1,fd2;

    fd0=open("/dev/null",O_RDWR);
    fd1=dup(fd0);
    fd2=dup(fd1);

這個操作是為 防止0,1,2的檔案操作符被使用。0是標準輸入,1是標準輸出,2是標準出錯。一旦被佔用,檔案內容會出錯。

實驗:

/*
 ============================================================================
 Name        : proteprocess.c
 Author      :
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */
//實驗目的:主程式每隔一分鐘
#include <stdio.h>
#include <stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
void init_doeman(void)
{
    umask(0);
    int i,fd0,fd1,fd2;
    if(fork()<0)
        exit(0);
    setsid();
    chdir("/");
    for(i=0;i<getdtablesize();i++)
    {
        close(i);
    }
    fd0=open("/dev/null",O_RDWR);
    fd1=dup(fd0);
    fd2=dup(fd1);
    //exit(0);
}
int main(void)
{
    FILE *fp;
    time_t t;
    init_doeman();
    while(1)
    {
        sleep(2);//每隔兩秒鐘報告一下執行狀態
        if((fp=fopen("test.log","a"))!=NULL)
        {
            t=time(0);
            fprintf(fp,"I am here at %s/n",asctime(localtime(&t)));
            fclose(fp);
        }

    }
    return EXIT_SUCCESS;
}


相關文章