守护进程的概念
守护进程(Deamon Process)是Linux三种进程(前台进程、批处理进程、守护进程)类型之一:是Linux中的后台服务进程,是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
特点:
始终在后台运行,独立于任何终端,周期性的执行某种任务或等待处理特定事件。
它是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?
之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。
由于在 Linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。
进程组(Process Group):进程集合,每个进程组有一个组长(Leader),其进程ID就是该进程组ID。
会话(Session):进程组集合,每个会话有一个组长,其进程ID就是该会话组ID。
控制终端(Controlling Terminal):每个会话可以有一个单独的控制终端,与控制终端连接的Learder就是控制进程(Contronlling Process)。
守护进程的创建
1、nohup 命令
nohup xxxx &
2、setsid函数
pid_t setsid(void);
成功返回进程的会话ID,失败返回-1,设置errmo。
调用setsid函数的进程,即使新的会长,也是新的组长。
1)创建子进程,父进程退出,则:
子进程变成孤儿进程,被init进程收养;
子进程在后台运行;
if (fork() > 0) {
exit(0);
}
2)子进程创建新会话
子进程成为新的会话组长;
子进程脱离原先的终端;
if (setsid() < 0) {
exit(-1);
}
3)更改当前(封装目录)工作目录(非必须)
守护进程一直在后台运行,其工作目录不能被卸载
重新设定当前工作目录cwd;
chdir("/");
chdir("/tmp");
4)重设文件权限掩码(非必须)
文件权限掩码设置为0;
只影响当前进程;
if (umask(0) < 0) {
exit(-1);
}
5)关闭打开的文件描述符
关闭所有从父进程继承的打开文件;
已脱离终端,stdin/stdout/stderr(标准输入0、标准输出1、标准错误2)无法再使用;
int i;
for (i = 0; i < 3; i++) {
close(i);
}
getsid函数:查看当前会话组组长
pid_t getsid(pid_t pid)
成功:返回调用进程的会话ID;失败:-1,设置errno
1.pid为0表示察看当前进程session ID
2.ps ajx命令查看系统中的进程。参数a表示不仅列当前用户的进程,也列出所有其他用户的进程,参数x表示不仅列有控制终端的进程,也列出所有无控制终端的进程,参数j表示列出与作业控制相关的信息。
3.组长进程不能成为新会话首进程,新会话首进程必定会成为组长进程。
getpid:获取进程id
pid_t getpid(void);
getpgid:获取进程组id
pid_t getpgid(pid_t pid);
守护进程的实现
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
int main(){
pid_t pid;
pid = fork();
if(pid<0){
perror("fork");
return 0;
}else if(pid>0){
exit(0);
// sleep(100);
}
printf("I am a deamon\n");
printf("sid=%d,pid=%d,pgid=%d\n",getsid(getpid()),getpid(),getpgid(getpid()));
if(setsid()<0){
perror("setsid");
exit(0);
}
printf("after sid=%d,pid=%d,pgid=%d\n",getsid(getpid()),getpid(),getpgid(getpid()));
chdir("/");
if(umask(0)<0){
perror("unmask");
exit(0);
}
close(0);
close(1);
close(2);
printf("after close \n");
sleep(100);
}