守护进程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhangze/article/details/79966735

Linux系统启动时,会启动很多系统服务进程,这些进程没有控制终端,也不能直接和用户进行交互,其他进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但系统服务进程不受用户登录注销的影响,它一直在运行着。这种进程也叫守护进程
守护进程特点:运行在后台;独立于控制终端,并且周期性的执行某种任务或等待某种事件的发生。
生命周期:一般在系统启动时开始运行,除非强行终止或关机,否则会一直运行。
权限:守护进程以超级用户权限运行,因为要使用特殊端口(1~1024)或访问某些特殊资源。
父进程:守护进程的父进程都是init进程。因为其父进程通常在创建守护进程后就结束掉了,由init进程领养,因此所有的守护进程都是孤儿进程。
输入输出:守护进程不能直接与用户进行交互,没有控制终端,因此其任何输出(包括标准输出与标准出错)都要经过特殊处理。
用指令

ps axj | more

查看系统中的进程,在TPGID一行为-1的进程都是没有控制终端的进程,也就是守护进程。

创建守护进程:
创建守护进程最关键的一步是调用setsid函数创建一个新的Session,并称为Session Leader。

#include <unistd.h>
pid  setsid(void);
返回值:调用成功返回新创建的Session的id(也是当前进程的id),失败返回-1

注意:调用这个函数前要保证当前进程不是当前进程组的Leader,通常进程组的第一个进程是这个进程组的Leader。因此可以调用fork函数后在子进程中创建新的Session。
成功调用该函数后的结果:
1、创建一个新Session,并成为Session Leader,Session的id就是这个进程的id。
2、创建一个新进程组,并成为进程组的Leader新进程组id就是这个进程的id。
3、如果当前进程原本有一个控制终端,则它失去这个控制终端,成为没有控制终端的进程。失去控制终端是指,这个终端依然是打开的,还可以读写,但仅仅是一个普通文件,而不是控制终端。

创建守护进程的一般步骤:
1、调用umask将文件模式创建屏蔽字设置为0。
2、调用fork函数,并且父进程退出。
3、利用setsid函数创建新会话。
4、忽略SIGCHLD信号。
5、再次调用fork,并且父进程退出(保持子进程非会话手进程,从而保证后续不会和其他终端相关联)(非必须)。
6、调用chdir函数将当前工作目录更改为根目录。
7、关闭不需要的文件描述符。

创建一个守护进程:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>

#define ERR_EXIT(m) \
    do\
    {\
        perror(m);\
        exit(EXIT_FAILURE);\
    }while(0)

void mydaemon()
{
    int fd0;
    time_t t;
    pid_t pid;
    struct sigaction sa;
    umask(0);

    if((pid = fork()) < 0)
        ERR_EXIT("fork");
    else if(pid > 0)
        exit(EXIT_SUCCESS);

    setsid();

    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if(sigaction(SIGCHLD, &sa, NULL) < 0)
        ERR_EXIT("sigaction");

    if((pid = fork()) < 0)
        ERR_EXIT("fork");
    else if(pid > 0)
        exit(EXIT_SUCCESS);

    if(chdir("/") < 0)
        ERR_EXIT("chdir");

    close(0);
    fd0 = open("/dev/null", O_RDWR);
    dup2(fd0, 1);
    dup2(fd0, 2);

    while(1)
    {
        fd0 = open("daemon.txt", O_WRONLY|O_CREAT|O_APPEND, 0644);
        if(fd0 == -1)
            ERR_EXIT("open");
        t = time(0);
        char *buf = asctime(localtime(&t));
        write(fd0, buf, strlen(buf));
        close(fd0);
        sleep(60);
    }
}

int main()
{
    mydaemon();

    return 0;
}

这里创建一个守护进程并每隔60秒向daemon.txt文件里面打印一次时间。
运行:
这里写图片描述
根目录下:
这里写图片描述
这样就创建了一个守护进程,用户注销后也依然存在。

也可以用系统函数daemon创建守护进程:

#include <unistd.h>
int  daemon(int nochdir,  int noclose);
参数:
nochdir:为0时当前目录变为根目录,否则不变。
noclose:为0时标准输入、标准输出和标准出错重导向为/dev/null,也就是不输出任何信息,否则照样输出。
返回值:内部调用了fork函数,如果fork成功则父进程调用_exit(2)退出,所以看到的错误信息都是子进程产生的。如果成功函数返回0,否则返回-1并设置errno。

示例:

#include <stdio.h>
#include <unistd.h>

int main()
{
    daemon(0, 0);
    return 0;
}

运行结果:
这里写图片描述
注意:这里创建的两个守护进程都要在root账户下才能成功,而如果守护进程没有重定向到根目录“/”下,普通用户也能创建成功。
最后杀死守护进程(root):
这里写图片描述

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页