守護進程是運行在后臺的一種特殊進程。它獨立于控制終端并且周期性地執行某種任務或等待處理某些發生的事件。守護進程是一種很有用的進程,Linux的大多服務器就是用守護進程實現的。
守護進程的創建步驟:
1.使進程在后臺運行(創建子進程,父進程退出)
if((pid=fork())>0)
exit(0);
else if (pid<0)
{
perror("fail to fork");
exit(-1);
}
2.脫離控制終端,登錄會話和進程組(創建新會話)
進程屬于一個進程組,進程組號進程組長的進程號。一個會話可以包含多個進程組,這些進程組共享一個控制終端,這個控制終端通常是創建進程的登錄終端??刂平K端,會話和進程組通常是從父進程繼承下來的。我們的目的就是要擺脫他們,使之不受他們的影響。方法是在第一點的基礎上,調用setsid()使進程成為會話組長:
setsid();
說明:當進程是會話組長時setsid()調用失敗。但第一點已經保證進程不是會話組長。setsid()調用成功后,進程成為新的會話組長和新的進程組長,并與原來的登錄會話和進程組脫離。由于會話過程對進程的獨占性,進程同時與控制終端脫離。
3.禁止進程重新打開控制終端
現在進程已成為無終端的會話組長,但它可以重新申請打開一個控制終端??梢酝ㄟ^使進程不在成為會話組長來禁止進程從新打開控制終端:
if(pid=fork())
exit(0); //結束第一子進程,第二子進程不在是會話組長
4.關閉所有文件描述符
進程從創建它的父進程那里繼承了打開的文件描述符。如不關閉,將會浪費系統資源,以及無法預料的錯誤。
close(0);
close(1);
close(2);
5.改變當前工作目錄:
進程活動時,其工作目錄所在的文件系統不能卸下。一般需要將工作目錄改變到根目錄。
chdir("\");
6.重設權限掩碼:
進程從創建它的父進程那里繼承了文件創建掩碼。它可能修改守護進程所創建的文件的存取位。為防止這一點,我們要將文件創建掩碼清除:
umask(0);
7.處理SIGCHLD信號:
處理SIGCHLD信號并不是必須的。但對于某些進程,特別是服務器進程往往在請求到來時生成子進程處理請求。如果父進程不等待子進程結束,子進程將成為僵尸進程,從而占用系統資源。如果父進程等待子進程的結束,將增加父進程的負擔,影響服務器進程的并發性能。
signal(SIGCHLD,SIG_IGN);
下面我們來看具體的代碼:(模擬實現簡單的守護進程)
my_daemon.c文件
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void my_daemon()
{
umask(0);
pid_t id1=fork();
if(id1<0)
{
perror("fork");
exit(1);
}
if(id1>0)
{
exit(0);
}
setsid();
pid_t id2=fork();
if(id2<0)
{
perror("fork");
exit(1);
}
if(id2>0)
{
exit(0);
}
signal(SIGCHLD,SIG_IGN);
chdir("/");
close(0);
close(1);
close(2);
}
int main()
{
my_daemon();
while(1)
{}
return 0;
}
運行結果結果如下:
我們可以看到有個進程號為1的進程,證明我們生成了守護進程。
下面是一個相對而言比較完整的守護進程,這個守護進程每隔一定時間向daemon.log文件輸出時間信息:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
void my_daemon()
{
umask(0);
pid_t id1=fork();
if(id1<0)
{
perror("fork");
exit(1);
}
if(id1>0)
{
exit(0);
}
setsid();
pid_t id2=fork();
if(id2<0)
{
perror("fork");
exit(1);
}
if(id2>0)
{
exit(0);
}
signal(SIGCHLD,SIG_IGN);
chdir("/");
close(0);
close(1);
close(2);
}
int main()
{
FILE* fp;
time_t t;
fp=fopen("daemon.log","a");
char *buf="hello bit";
my_daemon();
while(1)
while(1)
{
sleep(1);
t=time(0);
fprintf(fp,"this is a daemon: %s",asctime(localtime(&t)));
}
fclose(fp);
return 0;
}
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。