15,守护进程
概念:
守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
守护进程的特点:
守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符,控制终端,会话和进程组,工作目录以及文件
创建掩模等。这些环境通常是守护进程从执行它的父进程(特别是shell)中继承下来的。
守护进程的编程要点:
(1)后台运行
方法是父进程fork()出子进程后,父进程九退出
if(pid=fork())
exit(0);//是父进程,结束父进程,子进程继续
(2)脱离控制终端,登录会话和进程组
方法是调用setsid();
说明:当进程是会话组长时setsid()调用失败。但第一点已经保证进程不是会话组长。setsid()调用成功后,进程成为新的会话
组长和新的进程组长,并与原来的登录会话和进程组脱离。
(3)禁止进程重新打开控制终端
现在,进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端:
if(pid=fork())
exit(0);//结束第一子进程,第二子进程继续(第二子进程不再是会话组长)
(4)关闭打开的文件描述符
for(i=0;i 关闭打开的文件描述符close(i);>
(5)改变当前目录
进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。对于需要转储核心,
写运行日志的进程将工作目录改变到特定目录如/tmpchdir("/")
(6)重设文件创建掩模
进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点,将文件创建掩模清除:umask(0);
(7)处理SIGCHLD信号
signal(SIGCHLD,SIG_IGN);
- 守护进程实例:
- #include <unistd.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include <stdlib.h>
- #ifndef NOFILE
- #define NOFILE 3
- #endif
- void init_daemon()
- {
- int pid;
- int i;
- if(pid = fork()) exit(0); //父进程,退出
- else if(pid < 0) exit(1); //fork失败
- /* 子进程继续执行 */
- setsid(); //创建新的会话组,子进程成为组长,并与控制终端分离
- /* 防止子进程(组长)获取控制终端 */
- if(pid = fork()) exit(0); //父进程,退出
- else if(pid < 0) exit(1); //fork错误,退出
- /* 第二子进程继续执行 , 第二子进程不再是会会话组组长*/
- //for(i = 0; i < NOFILE; i++) /* 关闭打开的文件描述符*/
- //{
- //close(i);
- //}
- chdir("/tmp"); /* 切换工作目录 */
- umask(0); /* 重设文件创建掩码 */
- return;
- }
- int main()
- {
- FILE *fp;
- signal(SIGCHLD, SIG_IGN); /* 忽略子进程结束信号,防止出现僵尸进程 */
- init_daemon();
- while(1)
- {
- sleep(1);
- if((fp = fopen("/home/mantou/test.log", "a")) != NULL)
- {
- fprintf(fp, "%s\n", "test message");
- fclose(fp);
- }
- }
- return 0;
- }
补充:
(1)关于进程 struct rlimit结构体点击打开链接
在Linux系统中,Resouce limit指在一个进程的执行过程中,它所能得到的资源的限制,比如进程的core file的最大值,虚拟内存的最大值等。
Resouce limit的大小可以直接影响进程的执行状况。其有两个最重要的概念:soft limit 和 hard limit。
struct rlimit {
rlim_t rlim_cur;
rlim_t rlim_max;
};
(2)守护进程如何打印log
答:可以利用syslog()函数
(3)linux kernel启动用户空间init守护进程的代码
kernel/init/main.c 点击打开链接
目前我们至少知道在内核空间执行用户空间的一段应用程序有两种方法:
1. call_usermodehelper
2. kernel_execve