1、守护进程的基本流程
1、父进程创建子进程,父进程退出
守护进程是孤儿进程,但是是工程师人为创建的孤儿进程,低开销模式运行,对系统没有压力
2、子进程(守护进程)脱离控制终端,创建新会话
3、将守护进程中无用的描述符关闭(STDOUT|STDIN)
将STDERROR重定向到文件中,避免屏幕抛出异常信息,避免在使用前台时,后台的守护进程输出到屏幕上
需要把标准出错也要关闭,STDERR_FILENO,标准出错指的是,当使用open函数打开一个不存在文件时,会在终端上显示出来的错误
重定向函数dup和dup2
错误信息会通过STDERR_FILENO将异常抛出到显示器上,因此需要将错误信息重定向,不使用STDERR_FILENO流,而使用输出错误文件的文件描述符fd流
4、将守护进程的工作路径变为根目录
进程默认的工作目录一般为执行程序目录(app)
将默认工作目录(usb)改为目标电脑的根目录,避免工作目录丢失
5、修改进程umask文件权限掩码,变为0002
一般创建文件,文件权限是0664,6表示所有者权限,6表示同组用户权限,4表示其他人权限
一般电脑上初始权限mod为0666,但要与mask掩码0002做取反求与运算,得到0664
开发机的mod初始权限是0666,电脑权限掩码为0002,但目标主机的默认掩码不一定等于0002
将进程掩码改为0002,当进程创建文件时,创建出的文件掩码一定为0002
6、执行守护进程任务(间隔执行|条件触发|定时触发)
7、守护进程退出处理
测试任务
获取时间函数
用户传入数组地址,此函数将字符串时间写入数组中
设定数组中每个元素为time_t类型的变量tp
使用bzero函数初始化数组
使用time函数获取时间种子,赋值给tp
将时间种子tp传入ctime_r函数,计算出当前时间
ctime_r函数最后的返回值带'\n',因此使用tm[strlen(tm)-1]='\0'将'\n'去除
int Get_time(char* tm)
{time_t tp; bzero(tm,1024);tp=time(NULL);ctime_r(&tp,tm);tm[strlen(tm)-1]='\0';return 0;
}
创建进程的工作
void daemon_job(void)
{int fd;if((fd=open("system.log",O_RDWR|O_CREAT,0664))==-1){perror("open failed");}char tm[1024];char log_info[4096];while(1){Get_time(tm);sprintf(log_info,"<%s>WARING war informatcion...\n",tm);write(fd,log_info,strlen(log_info));bzero(log_info,sizeof(log_info));bzero(tm,sizeof(tm));sleep(3);}
}
创建守护进程
int create_daemon(void)
{pid_t pid;int efd;efd=open("ERROR_MSG",O_RDWR|O_CREAT,0664);pid=fork();if(pid>0){exit(0);}else if(pid==0){setsid();close(STDIN_FILENO);close(STDOUT_FILENO);dup2(efd,STDERR_FILENO);chdir("./");umask(0002);daemon_job();}else{perror("fork call failed");}return 0;
}
总代码
#include<stdio.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<signal.h>
#include<pthread.h>
#include<sys/fcntl.h>
#include<string.h>int Get_time(char* tm)
{time_t tp; bzero(tm,1024);tp=time(NULL);ctime_r(&tp,tm);tm[strlen(tm)-1]='\0';return 0;
}void daemon_job(void)
{int fd;if((fd=open("system.log",O_RDWR|O_CREAT,0664))==-1){perror("open failed");}char tm[1024];char log_info[4096];while(1){Get_time(tm);sprintf(log_info,"<%s>WARING war informatcion...\n",tm);write(fd,log_info,strlen(log_info));bzero(log_info,sizeof(log_info));bzero(tm,sizeof(tm));sleep(3);}
}int create_daemon(void)
{pid_t pid;int efd;efd=open("ERROR_MSG",O_RDWR|O_CREAT,0664);pid=fork();if(pid>0){exit(0);}else if(pid==0){setsid();close(STDIN_FILENO);close(STDOUT_FILENO);dup2(efd,STDERR_FILENO);chdir("./");umask(0002);daemon_job();}else{perror("fork call failed");}return 0;
}int main()
{create_daemon();return 0;
}
创建一个system.log的日志文件,每隔3秒,向日志文件中写入当前系统时间
eg:<系统时间>WARNING,test war message
2、实现Linux操作系统开机启动
shell脚本
脚本池里有许多脚本,每个脚本可以启动一个程序
虚拟机操作系统LINUX OS启动时,会将脚本池里的所有shell脚本对应的程序启动
编写一个shell脚本,让此脚本可以定位并启动守护程序