前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >13(守护进程)

13(守护进程)

作者头像
提莫队长
发布2019-02-21 11:04:38
7780
发布2019-02-21 11:04:38
举报
文章被收录于专栏:刘晓杰刘晓杰

13.2 守护进程的特征

守护进程是一种纯粹的后台进程,与运行前环境完全隔离,包括未关闭的文件描述符、控制终端、会话、进程组、工作目录以及文件创建掩码等 很多守护进程是父进程 fork 产生,所以会继承所有的父进程地址空间中的环境,所以必须在守护进程诞生之初,断绝这些相关环境,当然,守护进程也可以在 linux 系统启动时从启动脚本 /etc/rc.d 中启动,也可以由 crontab 启动 事实上,守护进程与普通进程的编写并没有特别大的区别

13.3 编程规则

(1)进程从创建他的父进程那里继承了文件创建掩码,它可能会修改守护进程创建的文件的存取位。因此需要调用:umask(0) (2)调用fork(),然后是父进程退出exit()。这样做实现了以下两点:第一,如果该守护进程是通过shell命令启动的,那么父进程终止使得shell认为该命令已执行完毕。第二,子进程继承了父进程的进程组ID,但有一个新的进程ID,这就保证了子进程不是组长进程。 (3)调用setsid()以创建一个新会话,使调用进程(a)成为新会话的首进程(b)成为一个新进程组的组长进程(c)没有控制终端 (4)将当前目录更改为根目录。调用int chdir (const char *path); (5)关闭打开的文件描述符。进程从创建它的父进程那里继承了打开的文件描述符,如不关闭,将会浪费系统资源。可以通过open_max()和getrlimit()来判断最高文件描述符值,并关闭直到该值的所有文件描述符。 (6)重定向标准输入、标准输出、错误输出 示例

代码语言:javascript
复制
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>     // for exit
#include <signal.h>     // for sigaction
#include <syslog.h>     // for syslog
#include <sys/stat.h>   // for umask
#include <sys/resource.h>
void daemonize (const char *cmd)
{
    int             i, fd0, fd1, fd2;
    pid_t           pid;
    struct rlimit       rl;
    struct sigaction    sa;

    // (1)更改文件权限屏蔽字 => 不屏蔽
    umask(0);

    if (getrlimit(RLIMIT_NOFILE, &rl) < 0)//得到最高文件描述符值
    {
        perror("getrlimit");
        exit(-1);
    }

    //(2)调用fork(),然后是父进程退出exit()
    if ((pid = fork()) < 0)//
    {
        perror("fork");
        exit(-1);
    }
    else if (pid != 0)
    {
        // 父进程退出
        exit(0);
    }

    //(3)调用setsid()创建一个新会话
    // 1. 脱离控制终端
    // 2. 成为组长进程
    // 3. 成为会话组首个进程
    setsid();

    // 忽略 SIGHUP 信号
    // 当终端退出,会发送该信号给会话组长进程,默认处理方式为退出
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    if (sigaction(SIGHUP, &sa, NULL) < 0)
    {
        perror("sigaction");
        exit(-1);
    }

    // 再次 fork 让守护进程不再担当会话组长,防止他重新打开终端
    if ((pid = fork()) < 0)
    {
        perror("fork");
        exit(-1);
    }
    if (pid != 0)
    {
        // 父进程退出
        printf("%d\n", pid);
        exit(0);
    }

    if (chdir("/") < 0)//(4)将当前目录更改为根目录
    {
        perror("chdir");
        exit(-1);
    }

    // (5)关闭所有文件描述符
    if (rl.rlim_max == RLIM_INFINITY)
        rl.rlim_max = 1024;
    for (i=0; i<rl.rlim_max; ++i)
        close(i);

    // 重定向标准输入、标准输出、错误输出到 /dev/null(5)
    fd0 = open("/dev/null", O_RDWR);
    fd1 = dup(0);
    fd2 = dup(0);

    openlog(cmd, LOG_CONS, LOG_DAEMON);
    if (fd0 != 0 || fd1 != 1 || fd2 != 2)
    {
        syslog(LOG_ERR, "unexpected file descriptors %d %d %d",
                fd0, fd1, fd2);
        exit(-1);
    }
    while (1)
    {
        // TODO
    }
}
int main (int argc, char *argv[])
{
    daemonize(argv[0]);
    return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年04月23日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 13.2 守护进程的特征
  • 13.3 编程规则
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档