Linux:守护进程解析、如何实现守护进程
1、守護進程:
守護進程也稱精靈進程(Daemon),是運行在后臺的?一種特殊進程。它獨立于控制終端且周期性地執行某種任務或等待處理某些發生的事件。守護進程是?一種很有用的進程。Linux的大多數服務器就是用守護進程實現的。比如,Internet服務器inetd,Web服務器httpd等。同時,守護進程完成許多系統任
?
務。比如,作業規劃進程crond等。Linux系統啟動時會啟動很多系統服務進程,
?
這些系統服務進程沒有控制終端,不能直接和用戶交互。其它進程都是在用戶
?
登錄或運行程序時創建,在運行結束或用戶注銷時終止,但系統服務進程不受用戶登錄注銷的影響,它們一直在運行著。這種進程有?一個名稱叫守護進程(Daemon)。
?
?
2、查看系統中的守護進程:
?
用ps axj命令查看系統中的進程(參數a表示不僅列當前用戶的進程,也列
?
出所有其他用戶的進程,參數x表示不僅列有控制終端的進程,也列出所有無控
?
制終端的進程,參數j表示列出與 作業控制相關的信息)。
?
凡是TPGID一欄寫著-1的都是沒有控制終端的進程,也就是守護進程。在
?
COMMAND一列用[] 括起來的 名字表示內核線程,這些線程在內核里創建,沒
?
有用戶空間代碼,因此沒有程序文件名和命令行, 通常采用以k開頭的名字,表
?
示Kernel。init進程我們已經很熟悉了,udevd負責維護/dev目錄下的 設備文
?
件,acpid負責電源管理,syslogd負責維護/var/log下的日志文件,可以看出,守護
?
進程通 常采用以d結尾的名字,表示Daemon。
?
?
3、自己實現守護進程:
(1)、調用umask將文件模式創建屏蔽字設置為0.
文件權限掩碼是指屏蔽掉文件權限中的對應位,比如一個文件權限掩碼是050它就屏蔽了文件擁有者得可讀與可寫權限,fork()創建的子進程會繼承父進程的文件權限掩碼,所以我們把文件權限掩碼設為0,可以增加子進程的靈活性,使用umask(0) 即可。
(2)、調用fork,父進程退出(exit)。
原因:
1)如果該守護進程是作為一條簡單的shell命令啟動的,那么父進程終止使得shell認為該命令已經執行完畢。
2)保證子進程不是一個進程組的組長進程。
?
守護進程需要脫離shell終端,造成一種程序關閉的假象,所有的工作都在子進程中完成,創建子進程,父進程退出,會造成子進程成為一個孤兒進程,在linux中當系統發現一個孤兒進程,就會1號進程(init進程)收養它,這樣子進程就變成init子進程了。代碼如下:
????? ???????????????????? ?????? if(fork() > 0)
?????????????????????????? ?????? {
???????????? ??????????????????????????? exit(0);
?????????????????????????????????? ?? }
(3)、 調用setsid創建一個新會話。setsid會導致:
1)調用進程成為新會話的首進程。
2)調用進程成為一個進程組的組長進程 。
3)調用進程沒有控制終端。(再次fork一次,保證daemon進程,之后不會打開tty設備)。
? NAME
?????? setsid -creates a session and sets the process group ID
?
SYNOPSIS
?????? #include<unistd.h>
?
?????? pid_tsetsid(void);
?
DESCRIPTION
??????setsid()? creates a new session ifthe calling process is not a process
?????? groupleader.? The calling process is theleader of? the? new?session,
?????? the? process group leader of the new processgroup, and has no control-
?????? lingtty.? The process group ID and session IDof the? calling? process
?????? are setto the PID of the calling process.? Thecalling process will be
?????? the onlyprocess in this new process group and in this new session.
?
RETURN VALUE
?????? Onsuccess, the (new) session ID of the calling?process? is? returned.
?????? On? error,?(pid_t) -1? is? returned,?and errno is set to indicate the
?????? error.
?
?????????? 該函數調用成功時返回新創建的Session的id(其實也就是當前進程的id),
??? 出錯返回-1。注意,調用這個函數之前,當前進程不允許是進程組的Leader,否則該函數返回-1。要保證當前進程不是進 程組的Leader也很容易,只要先fork再調用setsid就行了。fork創建的子進程和父進程在同一個進 程組中,進程組的Leader必然是該組的第?一個進程,所以子進程不可能是該組的第一個進程,在子進程中調用setsid就不會有問題了。成功調用該函數的結果是:
1. 創建一個新的Session,當前進程成為Session Leader,當前進程的id就是Session的id。
2. 創建一個新的進程組,當前進程成為進程組的Leader,當前進程的id就是進程組的id。
3. 如果當前進程原本有?一個控制終端,則它失去這個控制終端,成為一個沒有控制終端的進程。所謂失去控制終端是指,原來的控制終端仍然是打開的,仍然可以讀寫,但只是一個普通的打開文件而不是控制終端了。
?
(4)、禁止進程重新打開控制終端: 現在,進程已經成為無終端的會話組長。但它可以重新申請打開一個控制終端。可以通過使進程不再成為會話組長來禁止進程重新打開控制終端: ? if(pid=fork()) ???? exit(0); //結束第一子進程,第二子進程繼續(第二子進程不再是會話組長)?
(5)、將當前工作目錄更改為根目錄。
?
NAME
?????? setsid - creates a session and sets theprocess group ID
?
SYNOPSIS
?????? #include <unistd.h>
?
?????? pid_t setsid(void);
?
DESCRIPTION
?????? setsid()?creates a new session if the calling process is not a process
?????? group leader.? The calling process is the leader of? the?new? session,
?????? the?process group leader of the new process group, and has no control-
?????? ling tty.? The process group ID and session ID ofthe? calling? process
?????? are set to the PID of the callingprocess.? The calling process will be
?????? the only process in this new processgroup and in this new session.
?
RETURN VALUE
?????? On success, the (new) session ID of thecalling? process? is?returned.
?????? On?error,? (pid_t) -1? is?returned,? and errno is set toindicate the
?????? error.
?
(6)、關閉不再需要的文件描述符。
?
???????? ??? 進程從父進程中繼承了一些打開的文件描述符,不再需要使用時及時關閉,否則將會引起無法預料的錯誤和資源浪費。
???? ?Close(0);
???? ?Close(1);
???? ?Close(2);
???? ?即標準輸入、輸出、錯誤。
?
(7)、其他:忽略SIGCHLD信號。
??????????? ????? 處理SIGCHLD信號并不是必須的。 但對于某些進程,特別是服務器進程往往在請求到來時生成子進程處理請求。如果父進程不等待子進程結束,子進程將成為僵尸進程(zombie)從而占用系統資源。
??? 如果父進程等待子進程結束,將增加父進程的負擔,影響服務器進程的并發性能。在Linux下可以簡單地將 SIGCHLD信號的操作設為SIG_IGN。
?
signal(SIGCHLD,SIG_IGN);
?
? 這樣,內核在子進程結束時不會產生僵尸進程。
??? 這一點與BSD4不同,BSD4下必須顯式等待子進程結束才能釋放僵尸進程。
?
?
?
守護進程的完整代碼:
?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
?
void create_daemon()
{
?? pid_tpid;
?? umask(0);//設置文件掩碼
?
?? if(pid= fork() > 0)//調用fork()函數,父進程退出
?? {
????????? exit(0);
?? }
?? setsid();//設置新會話
?? signal(SIGCHLD,SIG_IGN);//處理SIGCHLD信號
?
?? if(pid= fork() < 0)// 禁止進程重新打開控制終端
?? {
????????? printf("forkerror");
????????? return;
?? }
?? elseif(pid != 0)
?? {
????????? exit(0);
?? }
?
?? chdir("/");//改變當前工作目錄
?
?? close(0);//關閉打開的不再需要的文件描述符
?? close(1);
?? close(2);
?
}
?
int main()
{
?? create_daemon();
?? while(1)
?? {
????????? sleep(1);
?? }
?
?? return0;
}
?
?
測試:
?
總結
以上是生活随笔為你收集整理的Linux:守护进程解析、如何实现守护进程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学会拒绝别人的6个技巧_多少人败在不懂拒
- 下一篇: Linux:shell脚本命令: /de