守护进程也称精灵进程( Daemon),是运行在后台的一种特殊进程。它独立于控制终端并
且周期性地执行某种任务或等待处理某些发生的事件。

Linux系统启动时会启动很多系统服务进程,这些系统服务进程没有控制终端,不能直接和用户交互。其它进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但系统服务进程不受用户登录注销的影响,它们一直在运行着。这种进程有一个名称叫守护进程(Daemon)。例如:udevd负责维/dev目录下的设备文件,acpid负责电源管理,syslogd负责维护/var/log下的日志文件,可以看守护进程通常采用以d结尾的名字,表示Daemon

精灵进程特点:自成进程组,自成会话,和终端无关(无数据交流),即tty为?。不能进行前后台控制,因为前后台是相对于终端来说,会话由前台进程和后台进程组成,而精灵进程自成会话。

精灵进程作用:提供服务。eg:内核线程:完成操作系统级别服务.

注销时:kill当前所有进程,精灵进程不受影响。

创建守护进程方法:

#include <unistd.h>

pid_t setsid(void);

注:调用这个函数之前,当前进程不允许是进程组的Leader,否则该函数返回-1。要保证当前进程不是进 程组的Leader也很容易,只要先fork再调用setsid就行了。 fork创建的父进程和子进程在同一个进程组中,进程组的Leader必然是该组的第一个进程,所以子进程不可能是该组的第一个进程,在子进程中调用setsid就不会有问题了。

成功调用该函数的结果是:
1. 创建一个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id。
2. 创建一个新的进程组,当前进程成为进程组的Leader,当前进程的id就是进程组的id。
3. 如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。所谓失去控制终端是指,原来的控制终端仍然是打开的,仍然可以读写,但只是一个普通的打开文件而不是控制终端了。

创建守护进程
1. 调用umask将文件模式创建屏蔽字设置为0.
2. 调用fork,父进程退出( exit。原因: 1)如果该守护进程是作为一条简单的shell命令启动的,那么父进程终止使得shell认为该命令已经执行完毕。 2)保证子进程不是一个进程组的组长进程。
3. 调用setsid创建一个新会话。
4. 将当前工作目录更改为根目录。

#include <unistd.h>

int chdir(const char *path);

On  success,  zero is returned.  On error, -1 is returned,

5. 关闭不在需要的文件描述符。
6. 其他:忽略SIGCHLD信号。

系统提供精灵化:

#include <unistd.h>

int daemon(int nochdir, int noclose);

#include<stdio.h>                                                               
#include<signal.h>
#include<stdlib.h>
void handle(int sig)
{
    //do nothing
}
void my_daemon()
{
    umask(0);
    pid_t tid=fork();//fork前单进程,父进程是进程组组长,fork后单进程,子进程不是进程组组长
    if(tid<0){
        ftok("fork");
        exit(1);
    }
    else if(tid>0){//father
        exit(0);
    }
    setsid();
     if(chdir("/")<0){
            printf("change dir error\n");
            return;
        }     
    close(0);
    close(1);
    close(2);
    signal(SIGCHLD,handle); 
}
int main()
{
    my_daemon();//精灵化,也可使用系统提供函数daemon(0,0);
    while(1);
    return 0;
}

wKiom1cu2lnClyzRAABVsECkkYs444.png

另一种实现:

#include<stdio.h>                                                               
#include<signal.h>
#include<stdlib.h>
void handle(int sig)
{
    //do nothing
}
void my_daemon()
{
    umask(0);
    pid_t tid=fork();
    struct sigaction act;
    if(sigemptyset(&act.sa_mask))
        return;
    act.sa_flags=0;
    act.sa_handler=handle;
    if(tid<0){
        ftok("fork");
        exit(1);
    }
    else if(tid>0){//father
        exit(0);
    }
        setsid();
    if(chdir("/")<0){
        printf("change dir error\n");
        return;
    }
    close(0);
    close(1);
    close(2);
    if(sigaction(SIGCHLD,&act,NULL)<0)
        return; 
}
int main()
{
    my_daemon();
    while(1);
    return 0;
}

wKiom1cyrsfy1KagAAAzwSdFWHU487.png

可发现上次运行得到的守护进程依然存在。

crond:

crond的概念和crontab是不可分割的。crontab是一个命令,常见于Unix和类Unix的操作系统之中,用于设置周期性被执行的指令。该命令从标准输入设备读取指令,并将其存放于“crontab”文件中,以供之后读取和执行。而crond正是它的守护进程.

       crontab -u //设定某个用户的cron服务 
  crontab -l //列出某个用户cron服务的详细内容 
  crontab -r //删除某个用户的cron服务 
  crontab -e //编辑某个用户的cron服务

  如果希望添加、删除或编辑crontab文件中的条目,而EDITOR环境变量设置为vi,那么就可以用vi来编辑crontab文件,相应的命令为:

  $ crontab -e

  可以像使用vi编辑其他任何文件那样修改crontab文件并退出。

时程表的格式如下:

f1 f2 f3 f4 f5 program

其中 f1 是表示分钟,f2 表示小时,f3 表示一个月份中的第几日,f4 表示月份,f5 表示一个星期中的第几天。program 表示要执行的程式。

当 f1 为 * 时表示每分钟都要执行 program,f2 为 * 时表示每小时都要执行程式,其余类推

当 f1 为 a-b 时表示从第 a 分钟到第 b 分钟这段时间内要执行,f2 为 a-b 时表示从第 a 到第 b 小时都要执行,其余类推

当 f1 为 */n 时表示每 n 分钟个时间间隔执行一次,f2 为 */n 表示每 n 小时个时间间隔执行一次,其余类推

当 f1 为 a, b, c,... 时表示第 a, b, c,... 分钟要执行,f2 为 a, b, c,... 时表示第 a, b, c...个小时要执行,其余类推。

使用者也可以将所有的设定先存放在档案 file 中,用 crontab file 的方式来设定时程表。

使用方式:

用VI编辑一个文件 cronfile,然后在这个文件中输入格式良好的时程表。编辑完成后,保存并退出。

在命令行输入

$: crontab cronfile

这样就将cronfile文件提交给cron进程,同时,新创建cronfile的一个副本已经被放在/var/spool/ cron目录中,文件名就是用户名。

1.创建hello.txt存储打印的消息

2.在当前目录创建hello.py脚本文件,脚本文件内容为

 print('hello')

3.crontab -e

打开一个crontab file并写入

*/1 * * * *   python /home/lxj/LinuxStudy/2016_5_8/hello.py >> /home/lxj        /LinuxStudy/2016_5_8/hello.txt

4.查看hello.txt内容

$ while : ; do sleep 1;cat hello.txt ;done

wKioL1cyxLajL_0WAAAehW1VvvU620.png

即周三打印消息为: 

 0 0 * * 3  python /home/lxj/LinuxStudy/2016_5_8/hello.py >> /home/lxj /LinuxStudy/2016_5_8/hello.txt