05_守护进程

什么是守护进程
 守护进程是在后台运行不受控端控制的进程,通常情况下守护进程在系统启动时自动运行
 守护进程的名称通常以d结尾,比如sshd、xinetd、crond等

ps -ajx
hzmct@U-64:/study/linuxtest/day01/04demon$ ps -ajx
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 1 1 ? -1 Ss 0 0:03 /sbin/init splash
0 2 0 0 ? -1 S 0 0:00 [kthreadd]
2 3 0 0 ? -1 S 0 0:00 [ksoftirqd/0]
2 5 0 0 ? -1 S< 0 0:00 [kworker/0:0H]

大多数守护进程没有控制终端,其终端名设置为问号,且以超级用户运行
内核守护进程以无控制终端方式启动
用户层守护进程缺少控制终端可能是守护进程是使用了setsid的结果
大多数守护进程都是进程组的组长进程以及是会话的首进程,而且是这些进程组合会话中的唯一进程。
用户层守护进程的父进程是init进程。
创建守护进程步骤
   调用fork(),创建新进程,它会是将来的守护进程
   在父进程中调用exit,保证子进程不是进程组组长
   调用setsid创建新的会话期
   将当前目录改为根目录 (如果把当前目录作为守护进程的目录,当前目录不能被卸载,它作为守护进程的工作目录了。)
   将标准输入、标准输出、标准错误重定向到/dev/null
守护进程api
int daemon(int nochdir, int noclose);
   功能:创建一个守护进程
   参数:
   nochdir:=0将当前目录更改至“/”
   noclose:=0将标准输入、标准输出、标准错误重定向至“/dev/null

Setsid创建一个新的会话;调用者进程会是这个会话期唯一的一个进程,是唯一组的组长;调用者进程id是组id,也是会话期的id。不能用进程组组长去调用setsid函数

有的进程有tty,有的进程没有tty。带问号的是守护进程。

hzmct     3640  3047  3640  3047  0 21:41 pts/9    00:00:00 ps -efj
hzmct@U-64:/study/linuxtest/day01/04demon$ killall  3639
3639: no process found
hzmct@U-64:/study/linuxtest/day01/04demon$ killall  dm01_mon

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

#include <sys/types.h>
#include <unistd.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <signal.h>
#include <errno.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
//#define S_IRUSR 00400//用户读
//#define S_IWUSR 00200//用户写
//#define S_IRGRP 00040//用户组读
//#define S_IWGRP 00020//用户组写
//#define S_IROTH 00004//其他读
//#define S_IWOTH 00002//其他写

//umask的使用
#if  0
#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
int test()
{
        printf("%x\n", RWRWRW);

        if(open("rwall", O_CREAT, RWRWRW) < 0) //enable read and write for all users
        {
            fprintf(stderr, "rwrwrw open error: %s!\n", strerror(errno));  //open error
            exit(-1);
        }
        //#define S_IRGRP 00040 define S_IWGRP 00020
        umask(S_IRGRP|S_IWGRP); //disable group for read and write
        if(open("nogrp", O_CREAT, RWRWRW) < 0)
        {
            fprintf(stderr, "nogrp open error: %s!\n", strerror(errno));   //open error
            exit(-1);
        }   
}
//-rw-rw-r-- 1 hzmct hzmct     0 8月  15 20:42 rwall
//-rw----rw- 1 hzmct hzmct     0 8月  15 20:42 nogrp

#endif
//调用官方api
#if 0
 int test()
 {
        //man daemon 可以看到
        //0表示改变重定向   1表示不改变
        daemon(1, 1);
        printf("test ...\n");
        for (;;) ;
        return 0;

 }
 /*
hzmct@U-64:/study/linuxtest/day01/04demon$ ./dm01_mon
test ...
hzmct@U-64:/study/linuxtest/day01/04demon$ ps -efj
UID        PID  PPID  PGID   SID  C STIME TTY          TIME CMD
hzmct     3597     1  3597  3597 99 21:36 ?        00:00:25 ./dm01_mon
hzmct@U-64:/study/linuxtest/day01/04demon$ kill -9 3597
*/
#endif
//手动实现daemon的功能
#if  1
   //int daemon(int nochdir, int noclose);
int my_daemon(int nochdir, int noclose)
{
    int i = 0;
    int fd0, fd1, fd2;
    pid_t pid;


    //如果守护进程要创建文件,则可能需要设置特定的权限
    //对于后面继承的文件模式会用到上面的屏蔽权限
    printf("%d\n", umask(0));


    pid = fork();
    if (pid == -1)
    {
        perror("fork err");
        exit(0);
    }

//1、使父进程退出
    if (pid > 0)
    {
        exit(0);
    }
    printf("pid:%d \n", getpid());

    /*
        setsid()建立一个新会话
        如果调用此函数的进程不是一个进程组组长,则此函数创建一个新会话
        1、该进程变成新会话的会话首进程(会话首进程是创建该会话的进程)
            此时该进程是会话的唯一进程。
        2、该进程成为一个新进程组的组长进程。新进程组id是该调用进程的进程id
        3、该进程没有控制终端


    */
    //2创建一个新会话
    pid = setsid();
    if (pid == -1)
    {
        perror("fork err");
        exit(0);
    }
    //3将当前目录改成根目录
    if (nochdir == 0)
        chdir("/");

    //4关闭0、1、2文件描述符
    if (noclose == 0)
    {
        for (i=0; i<3; i++)
        {
            close(i);
        }
    }

  //相当于把0号文件描述符之下/dev/null
    fd0 = open("/dev/null", O_RDWR); //fd文件描述符fd-0的文件描述符指向/dev/null 
    fd1 = dup(0);//把0号文件描述符 赋值给空闲的文件描述符 1
    fd2 = dup(0);//把0号文件描述符 赋值给空闲的文件描述符 2

    if(fd0 != 0 || fd1 != 1 || fd2 != 2)
    {
        //一定不会打印的
        printf("fd0 = %d  fd1 = %d  fd2 = %d\n", fd0, fd1, fd2);
    }


    while(1)
    {
        sleep(1);
    }

    printf("hello\n");
    return 0;
}


void test()
{
    my_daemon(0, 0);    
}
#endif

int main()
{
      test();
        return 0;
}

猜你喜欢

转载自blog.csdn.net/WUZHU2017/article/details/81711761