Linux进程实践(5) --守护进程
概述
? ?守護進程是在需要在后臺長期運行不受終端控制的進程,通常情況下守護進程在系統啟動時自動運行,在服務器關閉的時候自動關閉;守護進程的名稱通常以d結尾,比如sshd、xinetd、crond、atd等。
守護進程編程規則?
? ?調用umask將文件模式創建屏蔽字設置為一個已知值(通常是0)
? ?調用fork(),創建新進程,它會是將來的守護進程
? ?然后使父進程exit,保證子進程不是進程組組長
? ?調用setsid創建新的會話
? ?? ?會話:是一個或者多個進程組的集合,通常一個會話開始與用戶登錄,終止于用戶退出。在此期間,該用戶運行的所有進程都屬于這個會話期。
? ?將進程的當前目錄改為根目錄?(如果把當前目錄作為守護進程的目錄,當前目錄不能被卸載,它作為守護進程的工作目錄了。)
? ?關閉不再需要的文件描述符
? ?將標準輸入、標準輸出、標準錯誤重定向到/dev/null
setsid
pid_t setsid(void);?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?controlling?terminal.??The?process?group?ID?and?session?ID?of?the?calling?process?are?set?to?the?PID?of?the?calling?process.??The?calling?process??will?be?the?only?process?in?this?new?process?group?and?in?this?new?session.
/*當調用進程不是一個進程組的組長時,Setsid創建一個新的會話;調用者進程會是這個會話期唯一的一個進程,且是該進程組的組長;調用者進程id是組id,也是會話期的id。不能用進程組組長去調用setsid函數*/
//示例: int main() {pid_t pid = fork();if (pid == -1)err_exit("fork error");else if (pid != 0)exit(EXIT_SUCCESS);// //查看下面這一部分代碼在注釋的前后有什么變化 // pid_t id = setsid(); // if (id == -1) // err_exit("setsid error"); // else // cout << "new session id = " << id << endl;cout << "getpid = " << getpid() << endl;cout << "getpgid = " << getpgid(getpid()) << endl;return 0; }RETURN?VALUE
???????On??success,??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.
Linux中的守護進程API
int daemon(int nochdir, int noclose);參數:
? ?nochdir:=0將當前目錄更改至“/”
? ?noclose:=0將標準輸入、標準輸出、標準錯誤重定向至“/dev/null”
DESCRIPTION
???????The??daemon()??function?is?for?programs?wishing?to?detach?themselves?from?the?controlling?terminal?and?run?in?the?background?as?system?daemons.?If?nochdir?is?zero,?daemon()?changes?the?calling?process's?current?working??directory??to?the?root?directory?("/");?otherwise,?the?current?working?directory?is?left?unchanged.?If?noclose?is?zero,?daemon()?redirects?standard?input,?standard?output?and?standard?error?to?/dev/null;?otherwise,?no?changes?are?made?to?these?file?descriptors.
//示例:自己動手寫daemon函數(一個比較簡單的示例) bool myDaemon(bool nochdir, bool noclose) {umask(0);pid_t pid = fork();if (pid == -1)err_exit("fork error");else if (pid != 0) //parentexit(0);setsid();if (nochdir == 0)chdir("/");if (noclose == 0){int i;for (i=0; i < 3; ++i)close(i);open("/dev/null", O_RDWR); //相當于把0號文件描述符指向/dev/nulldup(0); //把0號文件描述符 賦值給空閑的文件描述符 1dup(0); //把0號文件描述符 賦值給空閑的文件描述符 2}return true; }//測試 int main(int argc, char *argv[]) {myDaemon(0, 0); //0表示做出改變(當前目錄,文件描述符),1表示不改變printf("test ...\n");while (true){sleep(1);}return 0; }//一個比較經典和完善的實例;來自《APUE》 #include "apue.h" #include <syslog.h> #include <fcntl.h> #include <sys/resource.h>bool myDaemon(const char *cmd);int main(int argc, char *argv[]) {myDaemon("xiaofang");while (true){sleep(1);}return 0; }bool myDaemon(const char *cmd) {umask(0);//Get maximum number of file descriptors.rlimit rlt;if (getrlimit(RLIMIT_NOFILE,&rlt) < 0){err_quit("%s: can't get file limit",cmd);}//Become a session leader to lose controlling TTY.pid_t pid = fork();if (pid == -1){err_quit("%s: can't fork",cmd);}if (pid != 0) //parent{exit(0);}setsid();//Ensure future opens won't allocate controlling TTYs.struct sigaction sa;sa.sa_handler = SIG_IGN;sigemptyset(&sa.sa_mask);sa.sa_flags = 0;if (sigaction(SIGHUP,&sa,NULL) < 0){err_quit("%s can't ignore SIGHUP",cmd);}if ((pid = fork()) < 0){err_quit("%s: can't fork",cmd);}else if (pid != 0) //Second Parent{exit(EXIT_SUCCESS);}//change the current working directory to the rootif (chdir("/") < 0){err_quit("%s: can't change directory to /",cmd);}//close all open file descriptionif (rlt.rlim_max == RLIM_INFINITY){rlt.rlim_max = 1024;}for (unsigned int i = 0; i < rlt.rlim_max; ++i){close(i);}//Attach file descriptors 0, 1, and 2 to /dev/null.int fd0 = open("/dev/null",O_RDWR);int fd1 = dup(0);int fd2 = dup(0);//Initialize the log file.openlog(cmd,LOG_CONS,LOG_DAEMON);if (fd0 != 0 || fd1 != 0 || fd2 != 0){syslog(LOG_ERR,"unexpected file descriptors %d %d %d",fd0,fd1,fd2);exit(EXIT_FAILURE);}return true; }
總結
以上是生活随笔為你收集整理的Linux进程实践(5) --守护进程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 务实云计算培训:帮您顺利走好云之旅
- 下一篇: Linux下的tree命令 --Lin