linux守护进程:
linux很多的系统服务都是守护进程,例如本地的系统服务crond计划任务 , 网络服务:web httpd
如何将一个进程转换为守护进程呢?
一.概念:
进程:
每一个进程都有父进程(祖先进程是INIT进程 ,PID 1)相关系统调用 fork();
子进程终止,父进程会得到通知,并且获取子进程的退出状态:相关:wait()
进程组:
每个进程也属于一个进程组;
每个进程组也有一个ID,ID是组长的PID;
一个进程只能为自己和子进程设置进程ID;
会话期(session):
会话期是一个或者多个进程组的集合;
setsid()可以建立一个会话期
如果setsid不是进程组的组长的话,会创建一个新的会话期.
1.此进程编程新的会话期的首进程组
2.此进程编程新的进程组的组长
3.脱离控制终端的关系
如果是子进程的组长的话,返回错误
为了保证这一点,所以我们先调用fork 然后再调用 exit
代码:
pid_t pid,sid;
pid = fork();
if(pid < 0)
{
exit(-1);//error
}
else if(pid > 0)
{
exit(0);//father exit(0)
}
else
{
sid = setsid();//child create
}
......
二.守护进程的特性
1.在后台运行的;
2.与当前的环境隔离开来,关闭文件描述符,控制终端,会话,以及文件掩码等等
3.启动方式 /etc/rc.d /etc/init.d/ shell crond(计划任务)
三.
编程要点:
1. pid = fork();
if(pid > 0)
{
exit(0);
}//关闭父进程
2. 脱离控制终端,登陆会话和进程组
以上都从父进程中继承来的,必须要摆脱他们,使之不受影响;
setsid();//一个函数搞定
/*关系 一对多
会话-》进程组-》进程*/
***失败原因:进程本来就是进程组的组长,但是第一步已经避免了
3.关闭打开的文件描述符
系统默认打开的文件描述符 标准输入,标准输出,标准错误(0,1,2);
close(STDIN_FILENO);标准输入
close(STDOUT_FILENO);标准输出
close(STDERR_FILENO);标准错误
4.改变当前目录
进程活动时,当前的工作目录所在的文件系统是不能卸载的,所以一般改工作目录到'/' root
chdir("/");
5.重新设置文件掩码umask
进程从创建的父进程哪里继承了文件掩码,所以需要重设umask(0);
以上基本上就完成了整个守护进程的操作;
代码实例:
void init_daemon()
{
pid_t pid,sid;
pid = fork();
if(pid < 0)
{
exit(-1);
}
else if(pid > 0)
{
exit(0);
}
else
{
sid = setsid();
}
chdir("\");
umask(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
linux很多的系统服务都是守护进程,例如本地的系统服务crond计划任务 , 网络服务:web httpd
如何将一个进程转换为守护进程呢?
一.概念:
进程:
每一个进程都有父进程(祖先进程是INIT进程 ,PID 1)相关系统调用 fork();
子进程终止,父进程会得到通知,并且获取子进程的退出状态:相关:wait()
进程组:
每个进程也属于一个进程组;
每个进程组也有一个ID,ID是组长的PID;
一个进程只能为自己和子进程设置进程ID;
会话期(session):
会话期是一个或者多个进程组的集合;
setsid()可以建立一个会话期
如果setsid不是进程组的组长的话,会创建一个新的会话期.
1.此进程编程新的会话期的首进程组
2.此进程编程新的进程组的组长
3.脱离控制终端的关系
如果是子进程的组长的话,返回错误
为了保证这一点,所以我们先调用fork 然后再调用 exit
代码:
pid_t pid,sid;
pid = fork();
if(pid < 0)
{
exit(-1);//error
}
else if(pid > 0)
{
exit(0);//father exit(0)
}
else
{
sid = setsid();//child create
}
......
二.守护进程的特性
1.在后台运行的;
2.与当前的环境隔离开来,关闭文件描述符,控制终端,会话,以及文件掩码等等
3.启动方式 /etc/rc.d /etc/init.d/ shell crond(计划任务)
三.
编程要点:
1. pid = fork();
if(pid > 0)
{
exit(0);
}//关闭父进程
2. 脱离控制终端,登陆会话和进程组
以上都从父进程中继承来的,必须要摆脱他们,使之不受影响;
setsid();//一个函数搞定
/*关系 一对多
会话-》进程组-》进程*/
***失败原因:进程本来就是进程组的组长,但是第一步已经避免了
3.关闭打开的文件描述符
系统默认打开的文件描述符 标准输入,标准输出,标准错误(0,1,2);
close(STDIN_FILENO);标准输入
close(STDOUT_FILENO);标准输出
close(STDERR_FILENO);标准错误
4.改变当前目录
进程活动时,当前的工作目录所在的文件系统是不能卸载的,所以一般改工作目录到'/' root
chdir("/");
5.重新设置文件掩码umask
进程从创建的父进程哪里继承了文件掩码,所以需要重设umask(0);
以上基本上就完成了整个守护进程的操作;
代码实例:
void init_daemon()
{
pid_t pid,sid;
pid = fork();
if(pid < 0)
{
exit(-1);
}
else if(pid > 0)
{
exit(0);
}
else
{
sid = setsid();
}
chdir("\");
umask(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}