2021-05-12 14:32:11
Linux守護行程解析
首先說一下後台進程與守護行程的區別
最大的區別有以下幾點:
(a)守護行程已經完全脫離終端控制台了,而後台程式並未完全脫離終端(在終端未關閉前還是會往終端輸出結果);
(b)守護行程在關閉終端控制台時不會受影響,而後台程式會隨使用者退出而停止,需要在以nohup command & 格式執行才能避免影響;
(c)守護行程的對談組和當前目錄,檔案描述符都是獨立的。後台執行只是終端進行了一次fork,讓程式在後台執行,這些都沒改變;
守護行程的特點
守護行程(Daemon)是在後台執行的一種特殊進程,它脫離於終端,從而這可避免進程被任何終端所產生的信號打斷,它在執行進程中的產生資訊也不在任何終端上顯示。守護行程週期性地執行某種任務或等待處理某些發生的事件,Linux的大多數伺服器就是用守護行程實現的。
守護行程程式設計要點
1.遮蔽一些有關控制終端操作的信號,是為了防止在守護行程沒有正常啟動起來前,控制終端受到干擾退出或掛起。程式碼如下:
/* 處理可能的終端信號 */
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGHUP , SIG_IGN);
2.在後台執行。
/* 是父進程,結束父進程,子進程繼續 */
if(fork())
exit(0);
3.脫離控制終端和行程群組:
(1)一個進程屬於一個行程群組,行程群組號(PGID)就是行程群組長的進程號(PID)
(2)同行程群組中的進程共用一個控制終端,這個控制終端預設是建立進程的終端
(3)一個進程關聯的控制終端和行程群組通常是從父進程繼承下來的,因此,這個子進程仍然受到父親進程終端的影響,因為終端產生的信號會傳送給前台行程群組的所有進程。
基於以上原因,需要讓為個子進程徹底擺脫該終端的影響,需要呼叫setsid()使子進程成為新的對談組長,程式碼如下:
setsid();
setsid()呼叫成功後,呼叫此函數的進程成為新的對談組長和新的行程群組長,並與原來的行程群組脫離關係。由於對談過程對控制終端的獨占性,進程同時與控制終端脫離。
4.禁止進程重新開啟控制終端,採用的辦法是再次建立一個子進程,並讓父親進程退出,該子進程不再是對談組長,從而達到目的。程式碼如下:
/* 結束第一子進程,第二子進程繼續 */
if(fork())
exit(0);
5.關閉開啟的檔案描述符。因為進程從建立它的父進程那裡繼承了開啟的檔案描述符,一般情況下不再需要。如不關閉,將會浪費系統資源。程式碼如下:
#define NOFILE 256
for(i=0; i<NOFILE; i++)
close(i);
6.改變當前工作目錄。進程活動時,其工作目錄所在的檔案系統不能解除安裝。因此需要將守護行程的工作目錄改變到合適的目錄。程式碼如下:
chdir("/tmp");
7.重設檔案建立掩碼。進程從建立它的父進程那裡繼承了檔案建立掩碼。它可能修改守護行程所建立的檔案的存取許可權。程式碼如下:
umask(0);
8.處理SIGCHLD信號(子進程退出信號)。如果不等待子進程結束,子進程將成為殭屍進程從而佔用系統核心資源。
/* 將子進程退出信號設為SIG_IGN,讓系統幫助回收進程資源 */
signal(SIGCHLD, SIG_IGN);
整體程式碼如下:
#define NOFILE 256
void DaemonMode()
{
int num = 0;
int fd0, fd1, fd2;
/* 遮蔽可能的信號 */
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGHUP , SIG_IGN);
if(fork())
exit(0);
setsid();
if(fork())
exit(0);
chdir("/tmp/httpd");
umask(0);
for(; num<NOFILE; num++)
close(num);
/* 將輸入、輸出重定向。因為之前描述符都關閉了,所以新開啟值為0、1、2 */
fd0 = open("/dev/null", O_RDWR);
fd1 = dup(0);
fd2 = dup(0);
signal(SIGCHLD, SIG_IGN);
}
補充 setsid() 函數功能:
如果呼叫進程已經是一個行程群組的組長,則此函數返回錯誤。為了杜絕這種情況,通常先呼叫fork()建立子進程,
然後使其父進程終止,而子進程繼續,在子進程中呼叫此函數。
如果呼叫此函數的進程不是一個行程群組組長,則此函數會建立一個新對談,呼叫setsid()函數的進程成為新的對談的領頭進程,
並與其父進程的對談組和行程群組脫離。由於對談對控制終端的獨占性,進程同時與控制終端脫離。
本文永久更新連結地址:http://www.linuxidc.com/Linux/2018-02/150773.htm
相關文章