Linux守护进程编写
环境:VMware 15 + ubuntu 16 内核:4.19
护进程的特点
-
后台服务程序,随系统启动而启动。
-
很多系统服务通过守护进程完成。
- 守护进程的名字往往以字母‘d’结尾
-
生存周期长。系统装入时启动,系统关闭时终止。
-
周期性的执行某种任务或等待处理某些特别的事件。
-
在Linux中,每一个与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端。但守护进程能突破这种限制,它从被执行开始,直到整个系统关闭时才退出.
依附:当控制终端被关闭时,依附于这个终端的进程都会自动的关闭。
守护进程编程一般步骤
-
第一步、创建子进程、父进程退出
编写守护进程的第一步就是使其独立与父进程,可以将父进程退出,子进程变成孤儿进程,并由init进程收养。为避免终端挂起,将父进程退出,造成程序已经退出的假象,所有后面的工作都在子进程完成,这样控制终端也可以继续执行其他命令,从而在形式上脱离控制终端的控制。
-
pid = fork(); //创建子进程
-
if (pid > 0)
exit(0); //父进程退出
-
-
第二步、在子进程中创建新的会话
经过第一步,子进程已经有后台运行,而在fork()的时候,子进程复制了大量父进程的PCB,包括会话、进程组、控制终端等信息。尽管父进程已经退出,但子进程的会话、进程组、控制终端的信息没有改变。为使子进程完全摆脱父进程的环境,需要调用 setsid 函数。
-
setsid( ) //让进程脱离控制终端。
通过调用 setsid 函数可以创建一个新会话,调用进程担任新会话的首进程,其作用有:
- 使当前进程脱离原会话的控制
- 使当前进程脱离原进程组的控制
- 使当前进程脱离原控制终端的控制
-
-
第三步、改变当前目录为根目录
-
chdir(“/”); //避免原工作目录不能被卸载
直接调用 chdir 函数将切换到根目录下。
由于进程运行过程中,当前目录所在的文件系统(如:“/mnt/usb”)是不能卸载的,为避免对以后的使用造成麻烦,改变工作目录为根目录是必要的。如有特殊需要,也可以改变到特定目录,如“/tmp”。
-
-
第四步、重设文件权限掩码
-
umask(0); // 文件权限掩码设置成为0
fork 函数创建的子进程,继承了父进程的文件操作权限,为防止对以后使用文件带来问题,需要重设文件权限掩码。调用 umask 设置文件权限掩码,通常是重设为 0,清除掩码,这样可以大大增强守护进程的灵活性。
权限掩码:设定了文件权限中要屏蔽掉的对应位。这个跟文件权限的八进制数字模式表示差不多,将现有存取权限减去权限掩码(或做异或运算),就可产生新建文件时的预设权限。
-
-
第五步、关闭文件描述符
-
for(i = 0;i < MAXFILE;i++)
close(i); //关闭继承自父进程的文件
同文件权限掩码一样,子进程可能继承了父进程打开的文件,而这些文件可能永远不会被用到,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸下,因此需要一一关闭它们。由于守护进程脱离了终端运行,因此标准输入、标准输出、标准错误输出这3个文件描述符也要关闭。通过调用函数 getdtablesize 返回进程文件描述符表中的项数(即打开的文件数目):
for (i=0; i < getablesize(); i++) close(i);
-
测试守护进程是否正常运行
/*
向文件/home/emmmm/Desktop/program.log中隔一秒钟写入时间
*/
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<time.h>
#include<string.h>
#include<stdlib.h>
int main(void){
pid_t child;
time_t rawTime;
struct tm *timeInfor;
FILE *pf;
child = fork();
if