专栏首页刘晓杰13(守护进程)

13(守护进程)

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)重定向标准输入、标准输出、错误输出 示例

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • UNPv2第一章:简介

    IPC是进程间通信(interprocess communication)的简称。传统上该术语描述的是运行在某个操作系统上的不同进程间的消息传递的不同方式。 ...

    提莫队长
  • UNPv1第四章:基本TCP套接口编程

    为了执行网络I/O,一个进程必须做的第一件事就是调用socket函数,指定期望的通信协议类型

    提莫队长
  • winform笔记

    FlowLayoutPanel控件不直接支持MouseWheel事件.即滚动滚轮也不会响应.所以必须手动来支持响应滚轮. FlowLayoutPanel控件...

    提莫队长
  • 操作系统核心原理-3.进程原理(上):进程概要

    进程管理、内存管理和文件管理是操作系统的三大核心功能,那么什么是进程呢?顾名思义,进程就是进展中的程序,或者说进程是执行中的程序。当一个程序被加载到内存之后就变...

    Edison Zhou
  • Node.js开发多进程应用

    使用child_process模块可以开启多个子进程,在多个子进程之间可以共享内存空间,可以通过子进程之间的互相通信来实现信息的交换,多个子进程之间也可以通过共...

    用户1515472
  • UNIX环境高级编程笔记之进程控制

      本章重点介绍了进程控制的几个函数:fork、exec族、_exit、wait和waitpid等,主要需要掌握的是父进程和子进程之间的运行机制,怎么处理进程的...

    CloudDeveloper
  • 僵尸进程

      在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等.但是仍然为其保留一定的信息(包括进程号the process ID,退出状态t...

    猿人谷
  • Linux进程基础

    计算机实际上可以做的事情实质上非常简单,比如计算两个数的和,再比如在内存中寻找到某个地址等等。这些最基础的计算机动作被称为指令 (instruction)。所谓...

    Vamei
  • 进程 · 全家桶

    fork调用一次返回两次 父进程中返回子进程id (就是大于0的意思) 子进程返回0 读时共享写时复制,可保高效

    看、未来
  • 再谈Android客户端进程保活

    在很多移动应用中,特别是即时通信类项目中,保活是一个永远无法避免的一个话题。保活,按照我的理解,主要包含两部分: 网络连接保活:如何保证消息接收实时性。 ...

    xiangzhihong

扫码关注云+社区

领取腾讯云代金券