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;
}

目录
相关文章
|
15天前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
39 1
|
3天前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
35 13
|
10天前
|
SQL 运维 监控
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
|
16天前
|
监控 算法 Linux
Linux内核锁机制深度剖析与实践优化####
本文作为一篇技术性文章,深入探讨了Linux操作系统内核中锁机制的工作原理、类型及其在并发控制中的应用,旨在为开发者提供关于如何有效利用这些工具来提升系统性能和稳定性的见解。不同于常规摘要的概述性质,本文将直接通过具体案例分析,展示在不同场景下选择合适的锁策略对于解决竞争条件、死锁问题的重要性,以及如何根据实际需求调整锁的粒度以达到最佳效果,为读者呈现一份实用性强的实践指南。 ####
|
15天前
|
缓存 监控 网络协议
Linux操作系统的内核优化与实践####
本文旨在探讨Linux操作系统内核的优化策略与实际应用案例,深入分析内核参数调优、编译选项配置及实时性能监控的方法。通过具体实例讲解如何根据不同应用场景调整内核设置,以提升系统性能和稳定性,为系统管理员和技术爱好者提供实用的优化指南。 ####
|
18天前
|
运维 监控 Linux
Linux操作系统的守护进程与服务管理深度剖析####
本文作为一篇技术性文章,旨在深入探讨Linux操作系统中守护进程与服务管理的机制、工具及实践策略。不同于传统的摘要概述,本文将以“守护进程的生命周期”为核心线索,串联起Linux服务管理的各个方面,从守护进程的定义与特性出发,逐步深入到Systemd的工作原理、服务单元文件编写、服务状态管理以及故障排查技巧,为读者呈现一幅Linux服务管理的全景图。 ####
|
23天前
|
缓存 算法 Linux
Linux内核的心脏:深入理解进程调度器
本文探讨了Linux操作系统中至关重要的组成部分——进程调度器。通过分析其工作原理、调度算法以及在不同场景下的表现,揭示它是如何高效管理CPU资源,确保系统响应性和公平性的。本文旨在为读者提供一个清晰的视图,了解在多任务环境下,Linux是如何智能地分配处理器时间给各个进程的。
|
1月前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
75 8
|
1月前
|
网络协议 Linux 虚拟化
如何在 Linux 系统中查看进程的详细信息?
如何在 Linux 系统中查看进程的详细信息?
61 1
|
1月前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
下一篇
DataWorks