來自:
守護程序在linux/unix系統中有著廣泛的應用。有時,開發人員也想把自己的程式變成守護程序。在建立乙個守護程序的時候,要接觸到子程序、程序組、會晤期、訊號機制、檔案、目錄和控制終端等多個概念。因此守護程序還是比較複雜的,在這裡詳細地討論linux/unix的守護程序的編寫,總結出八條經驗,並給出應用範例。
程式設計要點
1.遮蔽一些有關控制終端操作的訊號。防止在守護程序沒有正常運轉起來時,控制終端受到干擾退出或掛起。示例如下:
signal(sigttou,sig_ign);signal(sigttin,sig_ign);
signal(sigtstp,sig_ign);
signal(sighup ,sig_ign);
所有的訊號都有自己的名字。這些名字都以「sig」開頭,只是後面有所不同。開發人員可以通過這些名字了解到系統中發生了什麼事。當訊號出現時,開發人員可以要求系統進行以下三種操作:
◆ 忽略訊號。大多數訊號都是採取這種方式進行處理的,這裡就採用了這種用法。但值得注意的是對sigkill和sigstop訊號不能做忽略處理。
◆ 捕捉訊號。最常見的情況就是,如果捕捉到sigchid訊號,則表示子程序已經終止。然後可在此訊號的捕捉函式中呼叫waitpid()函式取得該子程序的程序id和它的終止狀態。另外,如果程序建立了臨時檔案,那麼就要為程序終止訊號sigterm編寫乙個訊號捕捉函式來清除這些臨時檔案。
◆ 執行系統的預設動作。對絕大多數訊號而言,系統的預設動作都是終止該程序。
對這些有關終端的訊號,一般採用忽略處理,從而保障了終端免受干擾。
這類訊號分別是,sigttou(表示後台程序寫控制終端)、sigttin(表示後台程序讀控制終端)、sigtstp(表示終端掛起)和sighup(程序組長退出時向所有會議成員發出的)。
2.將程式進入後台執行。由於守護程序最終脫離控制終端,到後台去執行。方法是在程序中呼叫fork使父程序終止,讓daemon在子程序中後台執行。這就是常說的「脫殼」。子程序繼續函式fork()的定義如下:
#include #include pid_t fork(void);
該函式是linux/unix程式設計中非常重要的函式。它被呼叫一次,但返回兩次。這兩次返回的區別是子程序的返回值為「0」,而父程序的返回值為子程序的id。如果出錯則返回「-1」。
3.脫離控制終端、登入會話和程序組。開發人員如果要擺脫它們,不受它們的影響,一般使用 setsid() 設定新會話的領頭程序,並與原來的登入會話和程序組脫離。這只是其中的一種方法,也有如下處理的辦法:
if ((fd = open("/dev/tty",o_rdwr)) >= 0)
其中/dev/tty是乙個流裝置,也是終端對映,呼叫close()函式將終端關閉。
4.禁止程序重新開啟控制終端。程序已經成為無終端的會話組長,但它可以重新申請開啟乙個控制終端。開發人員可以通過不再讓程序成為會話組長的方式來禁止程序重新開啟控制終端,需要再次呼叫fork函式。
上面的程式**表示結束第一子程序,第二子程序繼續(第二子程序不再是會話組長)。
5. 關閉開啟的檔案描述符,並重定向標準輸入、標準輸出和標準錯誤輸出的檔案描述符。程序從建立它的父程序那裡繼承了開啟的檔案描述符。如果不關閉,將會浪費系統資源,引起無法預料的錯誤。關閉三者的**如下:
for (fd = 0, fdtablesize = getdtablesize();fd < fdtablesize; fd++)
close(fd);
但標準輸入、標準輸出和標準錯誤輸出的重定向是可選的。也許有的程式想保留標準輸入(0)、標準輸出(1)和標準錯誤輸出(2),那麼迴圈應繞過這三者。**如下:
for (fd =3, fdtablesize = getdtablesize();fd < fdtablesize; fd++)
close(fd);
有的程式有些特殊的需求,還需要將這三者重新定向。示例如下:
error=open("/tmp/error",o_wronly|o_creat,0600);
dup2(error,2);
close(error);
in=open("/tmp/in",o_rdonly|o_creat,0600);
if(dup2(in,0)==-1) perror("in");
close(in);
out=open("/tmp/out",o_wronly|o_creat,0600);
if(dup2(out,1)==-1) perror("out");
close(out);
6.改變工作目錄到根目錄或特定目錄程序活動時,其工作目錄所在的檔案系統不能卸下。
一般需要將工作目錄改變到根目錄或特定目錄,注意使用者對此目錄需要有讀寫權。防止超級使用者解除安裝裝置時系統報告裝置忙。
7.處理sigchld訊號。sigchld訊號是子程序結束時,向核心傳送的訊號。
signal(sigchld,(void *)reap_status);
捕捉訊號sigchld,用下面的函式進行處理:
void reap_status()
8.在linux/unix下有個syslogd的守護程序,向使用者提供了syslog()系統呼叫。任何程式都可以通過syslog記錄事件。
由於syslog非常好用和易配置,所以很多程式都使用syslog來傳送它們的記錄資訊。一般守護程序也使用syslog向系統輸出資訊。syslog有三個函式,一般只需要用syslog(...)函式,openlog()/closelog()可有可無。syslog()在shslog.h定義如下:
#include void syslog(int priority,char *format,...);
其中引數priority指明了程序要寫入資訊的等級和用途。第二個引數是乙個格式串,指定了記錄輸出的格式。在這個串的最後需要指定乙個%m,對應errno錯誤碼。
應用範例
下面給出linux下程式設計的守護程序的應用範例,在unix中,不同版本實現的細節可能不一致,但其實現的原則是與linux一致的。
#include #include #include main(int argc,char **argv)}
docker學習 守護程序(二)
檢視docker守護程序是否啟動 ps ef grep docker或者 sudo status docker啟動命令 service docker start 或者 systemctl start docker停止命令 service docker stop 或者 systemctl stop d...
守護程序及守護程序輸出
1 建立乙個輸出程式 2 建立乙個守護程序 1 建立乙個輸出程式 守護程序不與終端聯絡,所以,需要另外建立乙個程式用於輸出。也可以直接使用 bin echo example daemon help.cc include int main int argc,char argv else if argc...
守護程序及守護程序輸出
1 建立乙個輸出程式 2 建立乙個守護程序 1 建立乙個輸出程式 守護程序不與終端聯絡,所以,需要另外建立乙個程式用於輸出。也可以直接使用 bin echo example daemon help.cc include int main int argc,char ar else if argc 2...