概述

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

    使用FFMPEG在windows平台下推rtmp流 工作中习惯在Linux下面使用FFmpeg模拟推rtmp流,无奈家中的电脑都是windows系统,需要利用家中的带宽来测试流媒体服务器的性能.所以研 ...

  2. MySQL NULL 值处理

    MySQL NULL 值处理 我们已经知道MySQL使用 SQL SELECT 命令及 WHERE 子句来读取数据表中的数据,但是当提供的查询条件字段为 NULL 时,该命令可能就无法正常工作. 为了 ...

  3. How To Automate Disconnection of Idle Sessions

    ***Checked for relevance on 30-Apr-2012*** goal: How to automate disconnection of idle sessions fact ...

  4. OpenCV RGB2LAB执行效率测试

    代码 #include <iostream> #include <vector> #include <opencv2/opencv.hpp> #define ERR ...

  5. 使用Spring Boot开发Web项目(二)之添加HTTPS支持

    上篇博客使用Spring Boot开发Web项目我们简单介绍了使用如何使用Spring Boot创建一个使用了Thymeleaf模板引擎的Web项目,当然这还远远不够.今天我们再来看看如何给我们的We ...

  6. 深入Java虚拟机(4)——网络移动性

    一.软件应用程序发展的几个阶段 软件应用程序发展经历了如下几个阶段: 服务于多个终端用户的大型计算机系统 孤立的个人计算机上运行孤立的软件 客户机/服务器模式 分布式处理模式 内容服务模式(网络移动性 ...

  7. 20160215.CCPP体系详解(0025天)

    程序片段(01):01.Malloc.c 内容概要:Malloc拓展 #include <stdio.h> #include <stdlib.h> //01.内存伸缩函数: / ...

  8. python模块:网络协议和支持

    python模块:网络协议和支持 webbrowser 调用浏览器显示html文件 webbrowser.open('map.html') [webbrowser - Convenient Web-b ...

  9. Swift Review总结:从 Swift Style 开始

    每个语言都有自己的推荐风格.显然OC与Swift有着不同的风格.当我们开始写Swift,首先要注意的就是按照Swift的风格写,而不是沿用OC的风格. 省略句末的分号 swift推崇简洁的语法.如果一 ...

  10. Unity角色残影特效

    残影特效在网上有很多例子,比如这个,我参考着自己整合了一下,算是整合了一个比较完整且特别简单易用的出来,只需要一个脚本挂上去无需任何设定就能用. 这里只针对SkinnedMeshRenderer的网格 ...