建立子進程,父進程退出
這是編寫守護進程的第一步。由於守護進程是脫離控制終端的,因此,完成第一步後就會在Shell終端裡造成一程式已經運行完畢的假象。之後的所有工作都在子進程中完成,而使用者在Shell終端裡則可以執行其他命令,從而在形式上做到了與控制終端的脫離。
在Linux中父進程先於子進程退出會造成子進程成為孤兒進程,而每當系統發現一個孤兒進程是,就會自動由1號進程(init)收養它,這樣,原先的子進程就會變成init進程的子進程。
在子進程中建立新會話
這個步驟是建立守護進程中最重要的一步,雖然它的實現非常簡單,但它的意義卻非常重大。在這裡使用的是系統函數setsid,在具體介紹setsid之前,首先要瞭解兩個概念:進程組和會話期
進程組:是一個或多個進程的集合。進程組有進程組ID來唯一標識。除了進程號(PID)之外,進程組ID也是一個進程的必備屬性。每個進程組都有一個組長進程,其組長進程的進程號等於進程組ID。且該進程組ID不會因組長進程的退出而受到影響。
會話周期:會話期是一個或多個進程組的集合。通常,一個會話開始與使用者登入,終止於使用者退出,在此期間該使用者啟動並執行所有進程都屬於這個會話期。
接下來就可以具體介紹setsid的相關內容:
(1)setsid函數作用:
setsid函數用於建立一個新的會話,並擔任該交談群組的組長。調用setsid有下面的3個作用:
讓進程擺脫原會話的控制
讓進程擺脫原進程組的控制
讓進程擺脫原控制終端的控制
那麼,在建立守護進程時為什麼要調用setsid函數呢?由於建立守護進程的第一步調用了fork函數來建立子進程,再將父進程退出。由於在調用了fork函數時,子進程全盤拷貝了父進程的會話期、進程組、控制終端等,雖然父進程退出了,但會話期、進程組、控制終端等並沒有改變,因此,還還不是真正意義上的獨立開來,而setsid函數能夠使進程完全獨立出來,從而擺脫其他進程的控制。
改變目前的目錄為根目錄
這一步也是必要的步驟。使用fork建立的子進程繼承了父進程的當前工作目錄。由於在進程運行中,目前的目錄所在的檔案系統(如“/mnt/usb”)是不能卸載的,這對以後的使用會造成諸多的麻煩(比如系統由於某種原因要進入單一使用者模式)。因此,通常的做法是讓”/”作為守護進程的當前工作目錄,這樣就可以避免上述的問題,當然,如有特殊需要,也可以把當前工作目錄換成其他的路徑,如/tmp。改變工作目錄的常見函數式chdir。
重設檔案許可權掩碼
檔案許可權掩碼是指屏蔽掉檔案許可權中的對應位。比如,有個檔案許可權掩碼是050,它就屏蔽了檔案組擁有者的可讀與可執行許可權。由於使用fork函數建立的子進程繼承了父進程的檔案許可權掩碼,這就給該子進程使用檔案帶來了諸多的麻煩。因此,把檔案許可權掩碼設定為0,可以大大增強該守護進程的靈活性。設定檔案許可權掩碼的函數是umask。在這裡,通常的使用方法為umask(0)。
關閉檔案描述符
同檔案許可權碼一樣,用fork函數建立的子進程會從父進程那裡繼承一些已經開啟了的檔案。這些被開啟的檔案可能永遠不會被守護進程讀寫,但它們一樣消耗系統資源,而且可能導致所在的檔案系統無法卸下。