學(xue)習(xi)Linux守護進程詳細(xi)筆記,讓你快(kuai)速學(xue)習(xi)
時間:2018-06-13 來源:未知(zhi)
Linux守護(hu)進程
一、 守護進程概述
守護(hu)進(jin)程(cheng)(cheng),也就是通常(chang)(chang)所說的(de)Daemon進(jin)程(cheng)(cheng),是Linux中的(de)后臺服務進(jin)程(cheng)(cheng)。它(ta)是一(yi)個生(sheng)存期(qi)較長的(de)進(jin)程(cheng)(cheng),通常(chang)(chang)獨立于控(kong)制終(zhong)端(duan)并且(qie)周期(qi)性的(de)執行(xing)某種任務或等待處(chu)理某些發(fa)生(sheng)的(de)事件。守護(hu)進(jin)程(cheng)(cheng)常(chang)(chang)常(chang)(chang)在系統(tong)啟動時(shi)(shi)開始運行(xing),在系統(tong)關閉時(shi)(shi)終(zhong)止。
Linux系統有很多(duo)守護進程(cheng)(cheng),大多(duo)數(shu)服(fu)(fu)務都是(shi)用守護進程(cheng)(cheng)實現的(de)。例如常見的(de)常見的(de)守護進程(cheng)(cheng)包括系統日志進程(cheng)(cheng)syslogd、 web服(fu)(fu)務器httpd、郵(you)件服(fu)(fu)務器sendmail和數(shu)據(ju)庫服(fu)(fu)務器mysqld等。
二(er)、進程與(yu)終端
在(zai)Linux中,每一個(ge)系統(tong)與用戶進行(xing)(xing)交流的(de)界面稱為終(zhong)端。從該終(zhong)端開始運行(xing)(xing)的(de)進程(cheng)都(dou)會依附于這個(ge)終(zhong)端,這個(ge)終(zhong)端稱為這些進程(cheng)的(de)控制終(zhong)端。當控制終(zhong)端被關閉時,相應的(de)進程(cheng)都(dou)會被自動關閉。
守(shou)護(hu)(hu)進程(cheng)能(neng)夠突破(po)這(zhe)種限(xian)制,它從開始運(yun)行(xing),直到(dao)整個(ge)系統關閉才會退出。如果想(xiang)讓某個(ge)進程(cheng)不會因為用戶或(huo)終端(duan)的(de)變(bian)(bian)化而受到(dao)影響,就必須把這(zhe)個(ge)進程(cheng)變(bian)(bian)成一個(ge)守(shou)護(hu)(hu)進程(cheng)。
三、 查看(kan)守護進程(cheng)
命令: ps axj

父進程ID : PPID
進程ID : PID
進(jin)程組ID : PGID
會話期ID : SID
終端ID : TTY
終端進程組(zu)ID : TPGID
狀態 : STAT
用戶 : UID
運行時(shi)間 : TIME
指令: COMMAND
四(si)、 Linux守護(hu)進程編寫(五步)

1. 創建子(zi)進(jin)程,父進(jin)程退出
第一(yi)步完(wan)成以后,子進程就(jiu)在形式上做到了與控(kong)制終端的脫離(li)
由于父(fu)進程(cheng)已經先于子進程(cheng)退出,子進程(cheng)變成(cheng)孤兒(er)進程(cheng)
pid = fork();
if (pid > 0) /*父進(jin)程退出*/
{
exit(0);
}
由于守護進程是脫離控制終(zhong)(zhong)端的(de)(de),因(yin)此,完(wan)成(cheng)第一步后就會(hui)在shell終(zhong)(zhong)端里造成(cheng)一程序已經運行完(wan)畢的(de)(de)假象。之后的(de)(de)所(suo)有后續工作都在子(zi)進程中完(wan)成(cheng),而用戶在shell終(zhong)(zhong)端里則可以執行其他的(de)(de)命令(ling),從(cong)而在形(xing)式上做到了(le)與控制終(zhong)(zhong)端的(de)(de)脫離
由(you)于(yu)父進(jin)(jin)(jin)(jin)程(cheng)(cheng)(cheng)已經先于(yu)子(zi)進(jin)(jin)(jin)(jin)程(cheng)(cheng)(cheng)退出,會造(zao)成子(zi)進(jin)(jin)(jin)(jin)程(cheng)(cheng)(cheng)沒有父進(jin)(jin)(jin)(jin)程(cheng)(cheng)(cheng),從(cong)而變成一個孤兒(er)進(jin)(jin)(jin)(jin)程(cheng)(cheng)(cheng)。在(zai)Linux中(zhong),每(mei)當系(xi)統發(fa)現(xian)一個孤兒(er)進(jin)(jin)(jin)(jin)程(cheng)(cheng)(cheng),就(jiu)會自動由(you)1號進(jin)(jin)(jin)(jin)程(cheng)(cheng)(cheng)收養。原(yuan)先的子(zi)進(jin)(jin)(jin)(jin)程(cheng)(cheng)(cheng)就(jiu)會變成init進(jin)(jin)(jin)(jin)程(cheng)(cheng)(cheng)的子(zi)進(jin)(jin)(jin)(jin)程(cheng)(cheng)(cheng)。
2. 在子進程(cheng)中(zhong)創建新會話
setsid()函數作用
setsid函(han)數用于創建(jian)一(yi)個新的會(hui)話(hua),并(bing)使(shi)得當前進(jin)程成為新會(hui)話(hua)組(zu)的組(zu)長setsid函(han)數能夠(gou)使(shi)進(jin)程完全獨立(li)出來,從而脫離(li)所有(you)其他進(jin)程的控制(zhi)。
進(jin)程(cheng)(cheng)(cheng)屬于一個(ge)進(jin)程(cheng)(cheng)(cheng)組,進(jin)程(cheng)(cheng)(cheng)組號(GID)就是(shi)(shi)進(jin)程(cheng)(cheng)(cheng)組長(chang)的(de)(de)進(jin)程(cheng)(cheng)(cheng)號(PID)。登(deng)錄會(hui)話(hua)可(ke)以包含多個(ge)進(jin)程(cheng)(cheng)(cheng)組。這些進(jin)程(cheng)(cheng)(cheng)組共享(xiang)一個(ge)控制終(zhong)端(duan)。這個(ge)控制終(zhong)端(duan)通常是(shi)(shi)創建進(jin)程(cheng)(cheng)(cheng)的(de)(de)登(deng)錄終(zhong)端(duan)。控制終(zhong)端(duan),登(deng)錄會(hui)話(hua)和進(jin)程(cheng)(cheng)(cheng)組通常是(shi)(shi)從父進(jin)程(cheng)(cheng)(cheng)繼承下來的(de)(de)。我(wo)們的(de)(de)目(mu)的(de)(de)就是(shi)(shi)要擺(bai)脫它(ta)們,使(shi)(shi)之不受(shou)它(ta)們的(de)(de)影響。方法是(shi)(shi)在第1點的(de)(de)基礎上,調用setsid()使(shi)(shi)進(jin)程(cheng)(cheng)(cheng)成為(wei)會(hui)話(hua)組長(chang)。
進程組
一個或多個進(jin)程(cheng)(cheng)的集合。進(jin)程(cheng)(cheng)組(zu)由進(jin)程(cheng)(cheng)組(zu)ID來唯一標識。每(mei)個進(jin)程(cheng)(cheng)組(zu)都有一個組(zu)長進(jin)程(cheng)(cheng),進(jin)程(cheng)(cheng)組(zu)ID就(jiu)是組(zu)長進(jin)程(cheng)(cheng)的進(jin)程(cheng)(cheng)號。
會話期
會話組是一個或(huo)多(duo)個進程組的集合
進程(cheng)組 對話期 終端

3. 修改當前工作目錄
chdir(“/tmp”);
通常的做(zuo)法是讓“/”或”/tmp”作為守護進程的當前工作目錄 。
在進程運行過(guo)程中,當前目錄(lu)所在的文(wen)件系統是不能(neng)卸載的。
chdir函數可(ke)以(yi)改變(bian)進程當(dang)前工作目錄
4. 重設置文(wen)件權限掩碼
umask(0);
文(wen)件(jian)權限掩(yan)碼是指文(wen)件(jian)權限中(zhong)被屏蔽掉的(de)對應位。把文(wen)件(jian)權限掩(yan)碼設置為0,可以(yi)增加(jia)該守護進程的(de)靈活性。設置文(wen)件(jian)權限掩(yan)碼的(de)函數umask();
5. 關閉文件(jian)描述符
fdtablesize = getdtablesize();
for (fd = 0; fd < fdtablesize; fd++)
close(fd);
新建(jian)的子(zi)進程會從(cong)父進程那里繼承(cheng)所有已經打開(kai)的文(wen)(wen)件(jian)。在創建(jian)完新的會話后,守護進程已經脫離(li)任何控制終(zhong)端,應當關閉用不(bu)到(dao)的文(wen)(wen)件(jian)。這些被打開(kai)的文(wen)(wen)件(jian)可(ke)能永遠(yuan)不(bu)會被守護進程讀或寫,但它(ta)們一樣(yang)消(xiao)耗系(xi)統資源,而且(qie)可(ke)能導致(zhi)所在的文(wen)(wen)件(jian)系(xi)統無法卸載
從終端(duan)輸(shu)入(ru)(ru)的字符(fu)(fu)不(bu)可能(neng)達到守護(hu)進(jin)程(cheng)(cheng),守護(hu)進(jin)程(cheng)(cheng)中(zhong)用常(chang)規(gui)的方法(如printf)輸(shu)出(chu)(chu)的字符(fu)(fu)也不(bu)可能(neng)在終端(duan)上顯示出(chu)(chu)來。所(suo)以,文(wen)件描述(shu)符(fu)(fu)為0、1和(he)2的三(san)個文(wen)件(對應標(biao)(biao)準(zhun)輸(shu)入(ru)(ru)、標(biao)(biao)準(zhun)輸(shu)出(chu)(chu)和(he)標(biao)(biao)準(zhun)錯誤這三(san)個流)已經失去了存在的意(yi)義(yi),也應被關閉。
五、 應用代碼舉例
創建一個守(shou)護進程每隔1s向daemon.txt文件中寫(xie)入一次系(xi)統(tong)時間。
#include
#include
#include
#include
#include
#include
#include
int main()
{
pid_t pid;
int num,i;
int fd;
time_t t;
char buf[100];
pid = fork();
//第一步:創建子進(jin)(jin)程(cheng)(cheng),父(fu)進(jin)(jin)程(cheng)(cheng)結(jie)束(子進(jin)(jin)程(cheng)(cheng)有init進(jin)(jin)程(cheng)(cheng)托管);
if(pid == 0)
{
//第二步(bu):創建(jian)新會話,脫離(li)(li)原來的(de)(de)進(jin)(jin)程,脫離(li)(li)控制終端,脫離(li)(li)原來的(de)(de)進(jin)(jin)程組;
setsid();
//第三步:修改當前(qian)(qian)目錄(lu)(lu),每一個進程都(dou)有一個當前(qian)(qian)目錄(lu)(lu);(不是必(bi)須的)
chdir("/tmp");
//第四步:重新設置文件權限(xian)掩碼(不是必須(xu)的)
umask(0);
//第五步:關閉打開(kai)的文件描述符(如果父進(jin)程(cheng)打開(kai)的文件,子進(jin)程(cheng)會繼(ji)承過來)
num = getdtablesize(); //獲得當前打開的文件(jian)描述(shu)符(fu)表
for(i = 0; i < num; i++)
{
close(i);
}
fd = open("daemon.txt",O_WRONLY | O_CREAT ,0666);
while(1)
{
t = time(0);
sprintf(buf,"time: %s\n",ctime(&t));
write(fd,buf,strlen(buf));
sleep(1);
}
}
else if(pid > 0)
{
exit(0);
}
return 0;
}

