《UNIX环境高级编程》笔记 第十三章-守护进程

1. 概念守护进程(daemon)是生存期长的一种进程。它们常常在系统引导装入时启动,仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的。Linux的大多数服务就是用守护进程实现的。这些守护进程名通常以d结尾,如inetd提供网络服务,sshd提供ssh登录服务,httpd提供web服务等待。大多数守护进程都以超级用户权限运行。所有守护进程都没有控制终端。用户层守护进程缺少控制终端可能是守护进程调用了setsid的结果(setsid会断开与控制终端的联系)。大多数用户
摘要由CSDN通过智能技术生成

1. 概念

守护进程(daemon)是生存期长的一种进程。它们常常在系统引导装入时启动,仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的

Linux的大多数服务就是用守护进程实现的。这些守护进程名通常以d结尾,如inetd提供网络服务,sshd提供ssh登录服务,httpd提供web服务等待。

  • 大多数守护进程都以超级用户权限运行

  • 所有守护进程都没有控制终端。用户层守护进程缺少控制终端可能是守护进程调用了setsid的结果(setsid会断开与控制终端的联系)。

  • 大多数用户层守护进程都是进程组的组长进程以及会话的首进程,而且是这些进程组和会话中的唯一进程

  • 用户层进程的父进程是init(1)进程。

2. 守护进程编程规则

编写守护进程程序时需要遵循一些基本规则,以防止产生不必要的交互作用。

  • 调用umask将文件模式创建屏蔽字设置为一个已知值(通常是0)。由继承(如fork)得来的文件模式创建屏蔽字可能会被设置为拒绝某些权限。如果守护进程要创建文件,那么它可能要设置特定的权限。

  • 调用fork,然后使父进程exit退出,这样会实现以下几点:

    • 如果该守护进程是shell命令启动的,那么父进程终止会让shell认为这条命令已经执行完毕
    • 虽然子进程继承了父进程的进程组ID,但是获得了一个新的进程ID,因此子进程不是该进程组的组长进程,这是接下来进行setsid调用的先决条件
  • 调用setsid创建一个新会话,这样会使调用进程:

    • 成为新会话的首进程
    • 成为新进程组的组长进程
    • 没有控制终端

    有些建议此时再次调用fork,终止父进程,继续使用子进程中的守护进程,这就保证了该守护进程不是会话首进程,可以防止它取得控制终端。

    为了避免取得控制终端的另一种方法是:当用open函数打开终端设备时,设置O_NOCTTY标志

  • 将当前工作目录更改为根目录

    从父进程处继承过来的当前工作目录可能在一个挂载的文件系统处。因为是守护进程通常在系统再引导前一直存在,所以如果守护进程的当前工作目录在一个挂载文件系统中,那么该文件系统就不能被卸载。

  • 关闭不再需要的文件描述符。这使得守护进程不再持有从其父进程继承来的任何文件描述符:可以通过getrlimit函数判定最高文件描述符值,并关闭直到该值的所有描述符。

  • 某些守护进程打开/dev/null使文件描述符0/1/2指向该文件。这样使得任何一个试图读标准输入、写标准输出或标准错误的例程都不会产生任何效果。因为守护进程不与终端设备关联,因此其输出无处显式,也无处从交互式用户那里接收输入。

    /dev/null文件:

    一个字符设备文件。称为空设备,它丢弃一切写入其中的数据(但报告写入操作成功),读取它则会立即得到一个EOF。

    /dev/null 被称为位桶(bit bucket)或者黑洞(black hole)。空设备通常被用于丢弃不需要的输出流,或作为用于输入流的空文件。这些操作通常由重定向完成。

    /dev/zero文件:

    一个字符设备文件。当你读它的时候,它会提供无限的空字符(NULL, 即0x00)。写入/dev/zero的内容会丢失不见。

    /dev/random和/dev/urandom文件:

    字符设备文件。随机数设备,提供不间断的随机字节流。二者的区别是/dev/random产生随机数据依赖系统中断,当系统中断不足时,/dev/random设备会“挂起”,因而产生数据速度较慢,但随机性好;/dev/urandom不依赖系统中断,数据产生速度快,但随机性较低。

**示例程序,初始化一个守护进程:**其中关于出错记录部分函数在下一节讲解

void daemonize(const char * cmd) {
   
    //清空文件模式创建屏蔽字
    umask(0);

    //获取最大文件描述符
    struct rlimit rl;
    if(getrlimit(RLIMIT_NOFILE,&rl) < 0) {
   
        perror("无法获取最大文件描述符");
    }

    //成为会话首进程并失去控制终端
    pid_t pid;
    if(fork() != 0) {
    // 父进程
        exit(0);
    }
    setsid();

    //确保该守护进程不会有控制终端
    struct sigaction sa;
    sa.sa_handler = SIG_IGN;
    sigemptyset
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值