守护进程理解和实现
守护进程:浅显一点的认识就是脱离用户终端的后台进程,当我们关闭终端时,该进程也不会退出。举个例子:比如我们远程登录一个linux系统,通过终端运行服务器程序,此时我们关闭终端退出来的时候,我们希望该服务器程序依然运行。此时就需要使该服务器进程是守护进程。
守护进程的实现步骤
- 创建子进程,父进程退出,子进程成孤儿进程
使子进程成为后天进程。 - 在子进程中创建新的会话,脱离控制终端
刚开始,一个会话组id对应一个终端,会话组里包含前台进程组和后台进程组。当关闭终端时,会话组里的所有进程都关闭。所以子进程要想脱离终端时,使用setsid()就可创建新的会话组,并且担任该会话组的组长,独立出终端。 - 改变当前工作目录为根目录
子进程会继承父进程的工作目录,由于在进程运行中,当前目录所在的文件系统是不能卸载的,这对以后使用会造成很多的麻烦。所以需要使用chdir改变子进程的工作目录为根目录。 - 重设文件权限掩码
文件权限掩码是屏蔽掉文件权限中的对应位。由于使用fork()函数新创建的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带了很多的麻烦(比如父进程中的文件没有执行文件的权限,然而在子进程中希望执行相应的文件这个时候就会出问题)。因此在子进程中要把文件的权限掩码设置成为0,即在此时有最大的权限,这样可以大大增强该守护进程的灵活性。设置的方法是:umask(0) - 关闭文件描述符
子进程会继承父进程的文件描述符,但是守护进程一般又用不到,所以一般全部关闭掉。 - 守护进程的退出,信号注册
通过kill命令,使守护进程退出,通常需要signal注册信号处理函数,进行退出处理。
示例代码
#include<stdio.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int main(){
pid_t pid;
char *buf="this is a dameon\n";
pid=fork();
if(pid>0){ //创建一个进程用来做守护进程
exit(0);
}
setsid(); //使子进程独立1.摆脱原会话控制 2.摆脱原进程组的控制 3.摆脱控制中端的控制
chdir("/"); //改变当前工作目录,这也是为了摆脱父进程的影响
umask(0); //重设文件权限掩码
int i;
for(i=0;i<1024;i++){ //关闭文件描述符(常说的输入,输出,报错3个文件),
close(i); //因为守护进程要失去了对所属的控制终端的联系,这三个文件要关闭
}
int fd=open("/tmp/dameon.txt",O_CREAT|O_WRONLY|O_APPEND,0777);
if(fd<0){
perror("open");
return -1;
}
while(1){
write(fd,buf,strlen(buf)+1);
sleep(5);
}
close(fd);
}