編寫Linux/Unix守護進程 [zz]
?編程要點
????1.屏蔽一些有關(guān)控制終端操作的信號。防止在守護進程沒有正常運轉(zhuǎn)起來時,控制終端受到干擾退出或掛起。示例如下:
|
????所有的信號都有自己的名字。這些名字都以“SIG”開頭,只是后面有所不同。開發(fā)人員可以通過這些名字了解到系統(tǒng)中發(fā)生了什么事。當(dāng)信號出現(xiàn)時,開發(fā)人員可以要求系統(tǒng)進行以下三種操作:
????◆ 忽略信號。大多數(shù)信號都是采取這種方式進行處理的,這里就采用了這種用法。但值得注意的是對SIGKILL和SIGSTOP信號不能做忽略處理。
????◆ 捕捉信號。最常見的情況就是,如果捕捉到SIGCHID信號,則表示子進程已經(jīng)終止。然后可在此信號的捕捉函數(shù)中調(diào)用waitpid()函數(shù)取得該子進程的進程ID和它的終止?fàn)顟B(tài)。另外,如果進程創(chuàng)建了臨時文件,那么就要為進程終止信號SIGTERM編寫一個信號捕捉函數(shù)來清除這些臨時文件。
????◆ 執(zhí)行系統(tǒng)的默認動作。對絕大多數(shù)信號而言,系統(tǒng)的默認動作都是終止該進程。
????對這些有關(guān)終端的信號,一般采用忽略處理,從而保障了終端免受干擾。
????這類信號分別是,SIGTTOU(表示后臺進程寫控制終端)、SIGTTIN(表示后臺進程讀控制終端)、SIGTSTP(表示終端掛起)和SIGHUP(進程組長退出時向所有會議成員發(fā)出的)。
????2.將程序進入后臺執(zhí)行。由于守護進程最終脫離控制終端,到后臺去運行。方法是在進程中調(diào)用fork使父進程終止,讓Daemon在子進程中后臺執(zhí)行。這就是常說的“脫殼”。子進程繼續(xù)函數(shù)fork()的定義如下:
|
????該函數(shù)是Linux/Unix編程中非常重要的函數(shù)。它被調(diào)用一次,但返回兩次。這兩次返回的區(qū)別是子進程的返回值為“0”,而父進程的返回值為子進程的ID。如果出錯則返回“-1”。
????3.脫離控制終端、登錄會話和進程組。開發(fā)人員如果要擺脫它們,不受它們的影響,一般使用 setsid() 設(shè)置新會話的領(lǐng)頭進程,并與原來的登錄會話和進程組脫離。這只是其中的一種方法,也有如下處理的辦法:
|
????其中/dev/tty是一個流設(shè)備,也是終端映射,調(diào)用close()函數(shù)將終端關(guān)閉。
????4.禁止進程重新打開控制終端。進程已經(jīng)成為無終端的會話組長,但它可以重新申請打開一個控制終端。開發(fā)人員可以通過不再讓進程成為會話組長的方式來禁止進程重新打開控制終端,需要再次調(diào)用fork函數(shù)。
????上面的程序代碼表示結(jié)束第一子進程,第二子進程繼續(xù)(第二子進程不再是會話組長)。
????5. 關(guān)閉打開的文件描述符,并重定向標(biāo)準輸入、標(biāo)準輸出和標(biāo)準錯誤輸出的文件描述符。進程從創(chuàng)建它的父進程那里繼承了打開的文件描述符。如果不關(guān)閉,將會浪費系統(tǒng)資源,引起無法預(yù)料的錯誤。關(guān)閉三者的代碼如下:
|
????但標(biāo)準輸入、標(biāo)準輸出和標(biāo)準錯誤輸出的重定向是可選的。也許有的程序想保留標(biāo)準輸入(0)、標(biāo)準輸出(1)和標(biāo)準錯誤輸出(2),那么循環(huán)應(yīng)繞過這三者。代碼如下:
|
????有的程序有些特殊的需求,還需要將這三者重新定向。示例如下:
|
????6.改變工作目錄到根目錄或特定目錄進程活動時,其工作目錄所在的文件系統(tǒng)不能卸下。
????一般需要將工作目錄改變到根目錄或特定目錄,注意用戶對此目錄需要有讀寫權(quán)。防止超級用戶卸載設(shè)備時系統(tǒng)報告設(shè)備忙。
????7.處理SIGCHLD信號。SIGCHLD信號是子進程結(jié)束時,向內(nèi)核發(fā)送的信號。
如果父進程不等待子進程結(jié)束,子進程將成為僵尸進程(zombie)從而占用系統(tǒng)資源。因此需要對SIGCHLD信號做出處理,回收僵尸進程的資源,避免造成不必要的資源浪費??梢杂萌缦抡Z句:
????signal(SIGCHLD,(void *)reap_status);
????捕捉信號SIGCHLD,用下面的函數(shù)進行處理:
|
????8.在Linux/Unix下有個syslogd的守護進程,向用戶提供了syslog()系統(tǒng)調(diào)用。任何程序都可以通過syslog記錄事件。
????由于syslog非常好用和易配置,所以很多程序都使用syslog來發(fā)送它們的記錄信息。一般守護進程也使用syslog向系統(tǒng)輸出信息。syslog有三個函數(shù),一般只需要用syslog(...)函數(shù),openlog()/closelog()可有可無。syslog()在shslog.h定義如下:
|
????其中參數(shù)priority指明了進程要寫入信息的等級和用途。第二個參數(shù)是一個格式串,指定了記錄輸出的格式。在這個串的最后需要指定一個%m,對應(yīng)errno錯誤碼。
????應(yīng)用范例
????下面給出Linux下編程的守護進程的應(yīng)用范例,在UNIX中,不同版本實現(xiàn)的細節(jié)可能不一致,但其實現(xiàn)的原則是與Linux一致的。
|
????此程序在Turbo Linux 4.0下編譯通過。這個程序比較簡單,但基本體現(xiàn)了守護進程的編程要點。讀者針對實際應(yīng)用中不同的需要,還可以做相應(yīng)的調(diào)整。