Linux进程实践(5) --守护进程

简介: 概述   守护进程是在需要在后台长期运行不受终端控制的进程,通常情况下守护进程在系统启动时自动运行,在服务器关闭的时候自动关闭;守护进程的名称通常以d结尾,比如sshd、xinetd、crond、atd等。

概述

   守护进程是在需要在后台长期运行不受终端控制的进程,通常情况下守护进程在系统启动时自动运行,在服务器关闭的时候自动关闭;守护进程的名称通常以d结尾,比如sshd、xinetd、crond、atd等。


守护进程编程规则 

   调用umask将文件模式创建屏蔽字设置为一个已知值(通常是0)

   调用fork(),创建新进程,它会是将来的守护进程

   然后使父进程exit,保证子进程不是进程组组长

   调用setsid创建新的会话

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

   将进程的当前目录改为根目录 (如果把当前目录作为守护进程的目录,当前目录不能被卸载,它作为守护进程的工作目录了。)

   关闭不再需要的文件描述符

   将标准输入、标准输出、标准错误重定向到/dev/null

setsid

pid_t setsid(void);

 setsid() creates a new session if the calling process is not a process group leader.  The calling process is the leader of the new session, the process group  leader  of  the  new process  group,  and has no controlling terminal.  The process group ID and session ID of the calling process are set to the PID of the calling process.  The calling process  will be the only process in this new process group and in this new session.

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

//示例:
int main()
{
    pid_t pid = fork();
    if (pid == -1)
        err_exit("fork error");
    else if (pid != 0)
        exit(EXIT_SUCCESS);

//    //查看下面这一部分代码在注释的前后有什么变化
//    pid_t id = setsid();
//    if (id == -1)
//        err_exit("setsid error");
//    else
//        cout << "new session id = " << id << endl;

    cout << "getpid = " << getpid() << endl;
    cout << "getpgid = " << getpgid(getpid()) << endl;

    return 0;
}

RETURN VALUE

       On  success,  the  (new)  session  ID  of  the  calling  process  is returned.  On error, (pid_t) -1 is returned, and errno is set to indicate the error.

Linux中的守护进程API

int daemon(int nochdir, int noclose);

参数:

   nochdir:=0将当前目录更改至“/”

   noclose:=0将标准输入、标准输出、标准错误重定向至“/dev/null”

DESCRIPTION

       The  daemon()  function is for programs wishing to detach themselves from the controlling terminal and run in the background as system daemons. If nochdir is zero, daemon() changes the calling process's current working  directory  to the root directory ("/"); otherwise, the current working directory is left unchanged. If noclose is zero, daemon() redirects standard input, standard output and standard error to /dev/null; otherwise, no changes are made to these file descriptors.

//示例:自己动手写daemon函数(一个比较简单的示例)
bool myDaemon(bool nochdir, bool noclose)
{
    umask(0);

    pid_t pid = fork();
    if (pid == -1)
        err_exit("fork error");
    else if (pid != 0)   //parent
        exit(0);

    setsid();

    if (nochdir == 0)
        chdir("/");
    if (noclose == 0)
    {
        int i;
        for (i=0; i < 3; ++i)
            close(i);
        open("/dev/null", O_RDWR);  //相当于把0号文件描述符指向/dev/null
        dup(0); //把0号文件描述符 赋值给空闲的文件描述符 1
        dup(0); //把0号文件描述符 赋值给空闲的文件描述符 2
    }

    return true;
}

//测试
int main(int argc, char *argv[])
{
    myDaemon(0, 0); //0表示做出改变(当前目录,文件描述符),1表示不改变
    printf("test ...\n");
    while (true)
    {
        sleep(1);
    }
    return 0;
}

//一个比较经典和完善的实例;来自《APUE》
#include "apue.h"
#include <syslog.h>
#include <fcntl.h>
#include <sys/resource.h>

bool myDaemon(const char *cmd);

int main(int argc, char *argv[])
{
    myDaemon("xiaofang");
    while (true)
    {
        sleep(1);
    }

    return 0;
}

bool myDaemon(const char *cmd)
{
    umask(0);

    //Get maximum number of file descriptors.
    rlimit rlt;
    if (getrlimit(RLIMIT_NOFILE,&rlt) < 0)
    {
        err_quit("%s: can't get file limit",cmd);
    }

    //Become a session leader to lose controlling TTY.
    pid_t pid = fork();
    if (pid == -1)
    {
        err_quit("%s: can't fork",cmd);
    }
    if (pid != 0)   //parent
    {
        exit(0);
    }
    setsid();


    //Ensure future opens won't allocate controlling TTYs.
    struct sigaction sa;
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGHUP,&sa,NULL) < 0)
    {
        err_quit("%s can't ignore SIGHUP",cmd);
    }
    if ((pid = fork()) < 0)
    {
        err_quit("%s: can't fork",cmd);
    }
    else if (pid != 0)  //Second Parent
    {
        exit(EXIT_SUCCESS);
    }

    //change the current working directory to the root
    if (chdir("/") < 0)
    {
        err_quit("%s: can't change directory to /",cmd);
    }

    //close all open file description
    if (rlt.rlim_max == RLIM_INFINITY)
    {
        rlt.rlim_max = 1024;
    }
    for (unsigned int i = 0; i < rlt.rlim_max; ++i)
    {
        close(i);
    }

    //Attach file descriptors 0, 1, and 2 to /dev/null.
    int fd0 = open("/dev/null",O_RDWR);
    int fd1 = dup(0);
    int fd2 = dup(0);

    //Initialize the log file.
    openlog(cmd,LOG_CONS,LOG_DAEMON);
    if (fd0 != 0 || fd1 != 0 || fd2 != 0)
    {
        syslog(LOG_ERR,"unexpected file descriptors %d %d %d",
        fd0,fd1,fd2);
        exit(EXIT_FAILURE);
    }

    return true;
}

目录
相关文章
|
23天前
|
网络协议 Linux
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
99 2
|
23天前
|
Linux Python
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
40 2
|
22天前
|
存储 人工智能 数据管理
深入理解Linux操作系统之文件系统管理探索人工智能:从理论到实践的旅程
【8月更文挑战第30天】在探索Linux的无限可能时,我们不可避免地会遇到文件系统管理这一核心话题。本文将深入浅出地介绍Linux文件系统的基础知识、操作命令及高级技巧,帮助你更有效地管理和维护你的系统。从基础概念到实践应用,我们将一步步揭开Linux文件系统的神秘面纱。
|
25天前
|
消息中间件 Linux
Linux进程间通信
Linux进程间通信
32 1
|
25天前
|
C语言
Linux0.11 系统调用进程创建与执行(九)(下)
Linux0.11 系统调用进程创建与执行(九)
20 1
|
25天前
|
存储 Linux 索引
Linux0.11 系统调用进程创建与执行(九)(上)
Linux0.11 系统调用进程创建与执行(九)
38 1
|
7天前
|
存储 监控 安全
探究Linux操作系统的进程管理机制及其优化策略
本文旨在深入探讨Linux操作系统中的进程管理机制,包括进程调度、内存管理以及I/O管理等核心内容。通过对这些关键组件的分析,我们将揭示它们如何共同工作以提供稳定、高效的计算环境,并讨论可能的优化策略。
17 0
|
19天前
|
Unix Linux
linux中在进程之间传递文件描述符的实现方式
linux中在进程之间传递文件描述符的实现方式
|
20天前
|
开发者 API Windows
从怀旧到革新:看WinForms如何在保持向后兼容性的前提下,借助.NET新平台的力量实现自我进化与应用现代化,让经典桌面应用焕发第二春——我们的WinForms应用转型之路深度剖析
【8月更文挑战第31天】在Windows桌面应用开发中,Windows Forms(WinForms)依然是许多开发者的首选。尽管.NET Framework已演进至.NET 5 及更高版本,WinForms 仍作为核心组件保留,支持现有代码库的同时引入新特性。开发者可将项目迁移至.NET Core,享受性能提升和跨平台能力。迁移时需注意API变更,确保应用平稳过渡。通过自定义样式或第三方控件库,还可增强视觉效果。结合.NET新功能,WinForms 应用不仅能延续既有投资,还能焕发新生。 示例代码展示了如何在.NET Core中创建包含按钮和标签的基本窗口,实现简单的用户交互。
43 0
|
25天前
|
存储 Linux 调度
Linux0.11 进程切换(十)
Linux0.11 进程切换(十)
13 0