概述

守护进程是在需要在后台长期运行不受终端控制的进程,通常情况下守护进程在系统启动时自动运行,在服务器关闭的时候自动关闭;守护进程的名称通常以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;
}

Linux进程实践(5) --守护进程的更多相关文章

  1. Linux编程之《守护进程》

    Intro ----- 守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程常 ...

  2. Linux 下Qt实现守护进程实例(转)

     原文地址:Linux守护进程的编程方法(含实例) 作者:lingdxuyan 参考文献 Linux信号列表(zz) Linux 守护进程的编程方法 linux上编写守护进程的例程 Linux下后台守 ...

  3. Linux进程托管与守护进程设置

    引言 在上一篇<Linux启动之旅>中,我们了解了Linux启动过程,在该过程的最后一步,init进程拉起/etc/init.d/rcN.d/目录下指定的守护进程(daemon).假若自定 ...

  4. Linux下一个简单守护进程的实现 (Daemon)

    在Linux/UNIX系统引导的时候会开启很多服务,这些服务称为守护进程(也叫Daemon进程).守护进程是脱离于控制终端并且在后台周期性地执行某种任务或等待处理某些事件的进程,脱离终端是为了避免进程 ...

  5. 一只简单的网络爬虫(基于linux C/C++)————守护进程

    守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程常常在系统引导装入时启动, ...

  6. (七) 一起学 Unix 环境高级编程(APUE) 之 进程关系 和 守护进程

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  7. python 进程锁 生产者消费者模型 队列 (进程其他方法,守护进程,数据共享,进程隔离验证)

    #######################总结######### 主要理解 锁      生产者消费者模型 解耦用的   队列 共享资源的时候 是不安全的 所以用到后面的锁 守护进程:p.daem ...

  8. python开发 *进程数据隔离.守护进程,进程同步工具 * 180725

    进程数据隔离.守护进程,进程同步工具 一.进程之间的数据隔离: from multiprocessing import Process n=100 #主程序中变量n= def func(): glob ...

  9. Python 之并发编程之进程中(守护进程(daemon)、锁(Lock)、Semaphore(信号量))

    五:守护进程 正常情况下,主进程默认等待子进程调用结束之后再结束守护进程在主进程所有代码执行完毕之后,自动终止kill -9 进程号 杀死进程.守护进程的语法:进程对象.daemon = True设置 ...

随机推荐

  1. 剑指架构师系列-spring boot的logback日志记录

    Spring Boot集成了Logback日志系统. Logback的核心对象主要有3个:Logger.Appender.Layout 1.Logback Logger:日志的记录器 主要用于存放日志 ...

  2. POJ 3050 Hopscotch DFS

    The cows play the child's game of hopscotch in a non-traditional way. Instead of a linear set of num ...

  3. Node.js HTTPS

    稳定性: 3 - 稳定 HTTPS 是基于 TLS/SSL 的 HTTP 协议.在 Node 里作为单独的模块来实现. 类: https.Server 这是 tls.Server 的子类,并且和 ht ...

  4. xshell连接centos与ubuntu

    操作系统:Windows 7 应用软件:Ware Workstation &Xshell 5 Linux:CentOS 7 Minimal &Ubuntu Server 16 ==== ...

  5. ZooKeeper之(六)应用实例

    6.1 Java API 客户端要连接 Zookeeper服务器可以通过创建 org.apache.zookeeper.ZooKeeper 的一个实例对象,然后调用这个类提供的接口来和服务器交互. Z ...

  6. javaweb异常提示信息统一处理(使用springmvc,附源码)

    一.前言 后台出现异常如何友好而又高效地回显到前端呢?直接将一堆的错误信息抛给用户界面,显然不合适. 先不考虑代码实现,我们希望是这样的: (1)如果是页面跳转的请求,出现异常了,我们希望跳转到一个异 ...

  7. Spark-SQL之DataFrame操作大全

    Spark SQL中的DataFrame类似于一张关系型数据表.在关系型数据库中对单表或进行的查询操作,在DataFrame中都可以通过调用其API接口来实现.可以参考,Scala提供的DataFra ...

  8. Ajax+Struts2实现验证码验证功能

    ---------------------------------------------------------------------------------------------------- ...

  9. Redis工作系列之一 与 Memcached对比理解

         近期公司项目在使用Redis,这几年Redis很火,Redis也常常被当作Memcached的挑战者被提到桌面上来.关于Redis与Memcached的比较更是比比皆是.然而,Redis真的 ...

  10. 使用spark ml pipeline进行机器学习

    一.关于spark ml pipeline与机器学习 一个典型的机器学习构建包含若干个过程 1.源数据ETL 2.数据预处理 3.特征选取 4.模型训练与验证 以上四个步骤可以抽象为一个包括多个步骤的 ...