Linux下守护进程

本文介绍了Linux下的守护进程,包括其定义、特性以及与普通进程的区别。详细讲解了如何创建守护进程,涉及在后台运行、创建新会话、禁止打开控制终端、关闭文件描述符、改变工作目录和重设文件创建掩模等步骤。还提到了/etc/rc.d目录的作用以及作业规划进程crond。通过实验代码和结果,加深了对守护进程的理解。

守护进程

什么是守护进程

独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件

特性:

  • 后台运行
  • 与运行前的环境隔离
  • 可从启动脚本/etc/rc.d启动,可从作业规划进程crond启动,也可由用户终端启动
/etc/rc.d目录作用

/etc/rc$.d 目录 通过它们所启动的守护进程具有超级用户的权限。系统的一些基本服务通常都是通过这种方式启动的。

1

从图中我们可以看到这个目录下的文件都是软链接到了init目录下,也就是说,他们是在系统启动进行初始化时启动的. 回到主题,仔细想一下的话就会发现这样做就可以保证第一点和第二点的条件 后台和运行前环境隔离.

作业规划进程crond

crond 是linux执行定时任务的一个Daemon,所以启动时便会自动运行,一直检查是否有要运行的进程 .有的话就去调度执行.

守护进程和普通进程区别

其实,我们大多数和操作系统的交互都是通过终端的,我们通过终端启动的进程,当我们关闭终端时,不管这个进程在前台或者后台运行.这个进程最终都会被kill掉,因为始终这个进程都是依附在终端上的.

而对于Daemon来说,它突破了这种局限, 在终端关闭时他也会继续运行.

举个例子:
如图,当我们用bash 启动spyder时,点击关闭bash,不管当前运行在前台和后台都会kill掉spyder. 第二图,没法演示,我这里关闭bash后自动kill掉了spyder

3
4

创建守护进程

在后台运行

这个实现比较简单,让父进程结束掉,子进程就成为了孤儿进程. 完成第一步后就会在shell终端里造成一个程序已经运行完毕的假象.

在子进程中创建新的会话(脱离控制终端):

我们在这里用到了系统函数setsid()来创建一个新的会话,并且担任该会话组的组长
补充:
进程组:是一个或多个进程的集合。进程组有进程组ID来唯一标识。除了进程号(PID)之外,进程组ID也是一个进程的必备属性。每个进程组都有一个组长进程,其组长进程的进程号等于进程组ID。且该进程组ID不会因组长进程的退出而受到影响。

会话周期:会话期是一个或者多个进程的集合。通常一个会话开始于用户的登录,终止于用户的退出,在此期间该用户运行的所有进程都属于这个会话期。

创建守护进程要调用setsid()函数的原因:调用了fork()函数的时候,子进程拷贝了父进程的会话期、进程组、控制终端等资源、虽然父进程退出了,但是会话期、进程组、控制终端等并没有改变. 所以创建一个新的会话摆脱原来的资源.

禁止进程重新打开控制终端

这里其实是为了控制程序员的,避免误打开控制终端.

关闭打开的文件描述符

进程从创建它的父进程那里继承了打开的文件描述符。如不关闭,将会浪费系统资源,造成进程所在的文件系统无法卸下以及引起无法预料的错误。

改变当前工作目录

进程活动时,其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。

重设文件创建掩模

由于使用fork()函数新创建的子进程继承了父进程的文件权限掩码,这就有问题了,假如我们父进程没有权限进行操作,那么子进程也会没有权限操作,我们将umask设置为0,相当于拥有了最大权限.

当前进程已经成为了无终端的会话组长,但是它还可以打开控制终端

实验代码

#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<sys/param.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
void initSpyderDaemon(){
    int pid;
    int i;
    if(pid=fork()) exit(0); //是父进程就结束父进程
    else if(pid<0) exit(1); //fork fail

    setsid();

    if(pid=fork()) exit(0);
    else if(pid<0) exit(1);

    for(i=0;i<NOFILE;i++) close(i);
    chdir("/");
    umask(0);
    system("spyder3"); //守护进程内启动spyder3 不会关闭

}
/**
*      父进程先结束,关闭bash,同样结束了spyder
*/
void initSpyder(){
    int pid;
    int i;
    if(pid=fork()) exit(0); //是父进程就结束父进程
    else if(pid<0) exit(1); //fork fail
    system("spyder3"); //守护进程内启动spyder3 不会关闭

}
int main(){
    //system("spyder3");
    //initSpyder();
    initSpyderDaemon();
    return 0;
}

实验结果

5
6
7
8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值