守護程序的單例項實現
為了正常工作,守護程序應該實現為單例項的,也就是在任一時刻只執行該守護程序的乙個副本,因為這個守護程序要排它的訪問乙個裝置。這裡需要用到文
件鎖的機制,如果守護程序建立乙個檔案,並且在整個檔案上加上一把鎖,那就只允許建立一把這樣的寫鎖,在此之後如果試圖再建立一把這樣的寫鎖就將失敗,以
此向續守護程序副本指明已經有乙個副本正在執行。而這個鎖檔案通常都放在/var/run目錄中,鎖檔案的名字通常是name.pid,其中name是此
守護程序的名字。注意,守護程序可能需要有root許可權才能在此目錄下建立檔案。
**實現及分析:
#includestdio.h>
#includesignal.h>
#includesyslog.h>
#includeunistd.h>
#includefcntl.h>
#includetime.h>
#includeerrno.h>
#includestring.h>
#includesys/stat.h>
#includesys/file.h>
#includesys/ioctl.h>
#includestdlib.h>
#define lockfile "/var/run/test.pid"
#define lockmode (s_irusr|s_iwusr|s_irgrp|s_iroth)
//成功返回0,若有錯誤返回-1,錯誤原因存於errno。
int lockfile(int ff)
void already_running(void)
if (lockfile(fd) 0)
syslog(log_err,"can』t lock %s: %s",lockfile,strerror(errno));
exit(1);
}//把fd指定的檔案大小改為0。引數fd為已開啟的檔案描述詞,而且必須是以寫入模式開啟的檔案。之所以要把檔案長度截短為0,是因為上乙個程序的id字串可以長於當前程序的id字串。
ftruncate(fd,0);
//把整型轉換成字串
sprintf(buf,"%d",getpid());
//把轉換成字串的程序id號寫入檔案/var/run/*.pid中
write(fd,buf,strlen(buf));
}int main(int argc,char *argv)
//脫離了控制終端還要脫離登入會話和程序組,這裡可以呼叫setsid()函式,呼叫成功後程成為新的會話組長和新的程序組長,並與原來的登入會話和程序組脫離,由於會話過程對控制終端的獨占性,程序同時與控制終端脫離。
/*if (setsid()
//要達到setsid()函式的功能也可以用如下處理方法。"/dev/tty"是乙個流裝置,也是終端對映,呼叫close()函式將終端關閉。
if ((fp=open("/dev/tty",o_rdwr)) >= 0)
//程序已經成為無終端的會話組長,但它可以重新申請開啟乙個新的控制終端。可以通過不再讓程序成為會話組長的方式來禁止程序重新開啟控制終端,需要再次呼叫fork函式。
if (fork() != 0)
//從父程序繼承過來的當前工作目錄可能在乙個裝配的檔案系統中。因為守護程序通常在系統重啟之前是一直存在的,所以如果守護程序的當前工作目錄在乙個裝配檔案系統中,那麼該檔案系統就不能被解除安裝。比如說從父程序繼承的當前目錄是/mnt下面的乙個被掛載的目錄。
if (chdir("/tmp") == -1)
//關閉開啟的檔案描述符,或重定向標準輸入、標準輸出和標準錯誤輸出的檔案描述符。程序從建立它的父程序那裡繼承了開啟的檔案描述符。如果不關閉,將會浪費系統資源,引起無法預料的錯誤。getdtablesize()返回某個程序所能開啟的最大的檔案數。
for (fd=0,fdtablesize=getdtablesize();fdfdtablesize;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);
*///由繼承得來的檔案方式建立的遮蔽字可能會拒絕設定某些許可權,所以要重新賦於所有許可權。
umask(0);
//如果父程序不等待子程序結束,子程序將成為殭屍程序(zombie)從而占用系統資源,如果父程序等待子程序結束,將增加父程序的負擔,影響伺服器程序的併發效能。因此需要對sigchld訊號做出處理,**殭屍程序的資源,避免造成不必要的資源浪費。
signal(sigchld,sig_ign);
//守護程序不屬於任何終端,所以當需要輸出某些資訊時,它無法像一般程式那樣將資訊直接輸出到終端,可以使用linux中自帶的syslogd守護程序,它向使用者提供了syslog()系統呼叫函式。資訊都儲存在/var/log/syslog檔案中。
syslog(log_user|log_info,"守護程序測試!\n");
//每隔60秒鐘就向/var/log/syslog日誌檔案裡寫入一次syslog()發出的資訊。
/* while (1)
*/while (1)
return 0;
守護程序之單例項守護程序
為了正常執行,某些守護程序實現為單例項的,也就是在任一時刻只執行該守護程序的乙個副本。例如,該守護程序可能需要排它地訪問乙個裝置。在cron守護程序情況下,如果同時有多個例項執行,那麼每個副本都可能試圖開始某個預定的操作,於是造成該操作的重複執行,這很可能導致出錯。如果守護程序需要訪問一裝置,而該裝...
守護程序之單例項
include include include include include include include include include include 建立守護程序函式 intdaemonize 重定向標準輸入 標準輸出和標準錯誤輸出 error open 0600 dup2 error,2...
守護程序的實現
6個步驟 步驟1 建立子程序,殺死父程序,目的是為了步驟2中呼叫setsid可以成功。步驟2 建立新會話,並自任組長。目的是脫離控制終端 會話組長呼叫 setsid 會失敗,步驟1建立的子程序必然不是會話組長,這就保證了 setsid 可以成功。步驟3 修改工作目錄為根目錄。當程序沒有結束時,工作目...