实验三 守护进程
一、实验目的
1、了解守护进程的生命周期及应用。
2、掌握编写守护进程的五个基本步骤。
二、实验原理
1、守护进程是运行在后台的一种特殊进程,用于周期性地执行某种任务或等待处理某些发生的事件。
2、守护进程生存期较长,常常在系统引导装入时启动,在系统关闭时终止。守护进程的名称通常以d结尾。
3、编写守护进程的五个步骤:
(1)fork()创建子进程,exit()退出父进程。
(2)setsid()在子进程中创建新会话,使子进程脱离原来的控制。
(3)chdir()改变当前的工作目录为根目录,防止可卸载的文件系统被占用。
(4)umask()设置文件权限掩码,防止继承来的文件创建屏蔽字,拒绝某些权限。
(5)close()关闭文件描述符,由于子进程从父进程继承一些打开的无用的文件,
需要将其关闭,防止占用资源
三、实验内容
1、编写守护进程test.c,test每5秒钟打印一个数字,定向输出到trush.txt。
2、编写并编译monitor.c,其功能为每5秒检测一次test是否正在运行;若未运行,则运行该程序。
3、先验证test是否能正常运行,需要执行test,然后查看数字是否正常输出至trush.txt。
4、执行kill命令终止进程,使用命令查看test此时并未运行。
5、执行monitor,5秒钟后使用命令查看test此时已经运行。
选做部分:将编写的守护进程设置为开机自启动。
四、实验过程
实验代码:
Test.c:
#include<unistd.h>
#include <signal.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/param.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<syslog.h>
#include <fcntl.h>
int main(int argc, char *const *argv){
int pc;
int k=0;
FILE *fp;
pc=fork();//创建子进程
if(pc<0)
{
printf("fork error\n");
exit(1);
}
else if(pc>0)
{
exit(0);//第二步,父进程退出
}
else
{
setsid();//第三步,创建新会话
chdir("/");//第四步,将当前目录改为根目录
umask(0);//第五步,重新设置文件权限掩码
for (int i = 0; i < getdtablesize(); ++i) {
close(i);}//第六步,关闭文件描述符
while(1){
k++;
sleep(5);
fp=fopen("/home/mj/sy3/trush.txt","a");
if(fp>=0){
fprintf(fp,"%d\n",k);
fclose(fp);
}
}
}
return 0;
}
Monitor.c:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
pid_t pid = 0;
pid = fork();
if(pid<0){
exit(-1);
}
if(pid>0){
exit(0);
}
pid = setsid();
if(pid<0){
exit(-1);
}
chdir("/");
umask(0);
int i=0;
for(i=0;i<getdtablesize();i++){
close(i);
}
int num=0;
while(1){
char buff[128]={0};
FILE *fp1 =NULL;
fp1 = popen("ps -ef | grep '/test'","r"); //执行ps -ef | grep '/test’这个命令
fread(buff,1,127,fp1); //将这个命令里的内容输出到buff数组中
pclose(fp1);
const char pattern[] = "/home/mj/test";
char *p = strstr(buff, pattern); // 字符串比较函数 看buff数组里是否有守护进程的路径
if(NULL ==p){ //若守护进程未启动
FILE *fp2 = NULL;
fp2 = popen("~/test","r");//使用popen()函数启动
pclose(fp2);
}
sleep(5); //每隔五秒检测一次
}
return 0;
};
实验截图:
选做部分:将编写的守护进程设置为开机自启动
①编写mot.sh文件,写入守护进程test的路径
②/etc/profile文件为系统的每个用户设置环境变量信息,所以将mot.sh文件所在的路径写入/etc/profile,这样test就能开机自启动了
③重新启动,输入ps -ef命令,可以看到/home/mj/test已经启动了
六、实验总结
守护进程是一种长期运行的进程,在后台运行,它是独立于控制终端的,使一个进程成为守护进程的步骤为:1)fork()创建子进程,父进程exit()退出;2)在子进程调用setsid()创建新会话,释放与控制终端之间的关联关系;3)在子进程中调用chdir()让根目录“/”成为子进程的工作目录,这里在上课时不太理解,在做实验时查阅资料才明白假如在/tmp/dada目录下创建一个守护进程,守护进程运行之后,这个目录可能没有任何用处了,你需要卸载它,但是守护进程在这个目录下运行,你便不能卸载4)在子进程中调用umask()重设文件权限掩码为0,以确保进程创建一个文件或者目录时候拥有所需权限;5)在子进程中close()不需要的文件描述符;
monitor.c监视test的原理为,先使用popen函数来执行ps命令,并把结果输出到一个数组中,然后看test的路径名是否在这个数组中,如果没有的话,说明test并未启动,此时就再次调用popen函数启动test。在实验时注意,如果同时运行多次test,那么他们都会往trush.txt文件中写入内容