UNIX环境C语言编程(10)-守护进程

本文深入解析守护进程的特征、编码实现、单实例机制及客户机/服务器模型应用,详细阐述如何创建守护进程,讨论其在系统中的作用,并介绍其在配置文件更新、文件与记录锁机制、以及并发处理等方面的关键操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、守护进程的特征

英文名称 daemon ,又称为常驻进程、精灵进程
守护进程有以下特征:
1 、长时间后台运行,通常随系统启停而启停
2 、大多系统守护进程具有 root 权限
3 、没有控制终端
4 、所有用户级别(非内核级别)的守护进程都是进程组长、会话领导,

        并且是进程组与会话中的唯一一组进程

5 、大多守护进程的父进程都是 init 进程

 

2、编码规则

如果编码实现一个守护进程,需要考虑哪些因素:
1 、将文件创建掩码 umask 设置为 0
2 、调用 fork ,然后父进程退出,目的:

        shell能够接收下一条指令;

        子进程不是进程组长,这是调用setsid函数的先决条件

3 、调用 setsid 创建一个新的会话

        当前进程成为新会话的领导、成为新进程组的组长、没有控制终端

4 、将当前工作目录改变为根目录 /
5 、关闭不再需要的文件描述符
6 、一些 daemon 进程将描述符 0 1 2 重定向为 / dev /null 设备
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

void z_daemon(void)
{
    pid_t  childpid = 0;
    struct sigaction sa;

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    /* 忽略信号 */
    sa.sa_handler = SIG_IGN;
    sigaction(SIGQUIT, &sa, NULL);
    sigaction(SIGHUP,  &sa, NULL);
    sigaction(SIGINT,  &sa, NULL);
    sigaction(SIGPIPE, &sa, NULL);

#ifdef SA_NOCLDSTOP
    sa.sa_flags |= SA_NOCLDSTOP;
#endif
#ifdef SA_NOCLDWAIT
    sa.sa_flags |= SA_NOCLDWAIT;
#endif

    sigaction(SIGCHLD, &sa, NULL);

    if( getppid() == 1 ) return;

    fflush(stdout); fflush(stderr);

    umask(0);

    childpid = fork();
    if( childpid < 0 ) exit(0);
    else if( childpid > 0 ) exit(0);

/*  the first child process  */
    if( setsid() == (pid_t) (-1) ) exit(0);

    childpid = fork();
    if( childpid < 0 ) exit(0);
    else if( childpid > 0 ) exit(0);

/*  the second child process */
    return;
}


3、单实例守护进程

即只能启动一个实例,不能多个实例同时运行
如果做到这一点?
文件与记录锁机制提供了一种简便的互斥机制
一个进程放置 锁后,其它进程后续的加锁尝试都会失败
另外,进程退出后,文件锁会自动释放,免除了手工清理的麻烦
文件锁机制在下一章节详述,一个简单示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

#define LOCKFILE "daemon.pid"
#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)

int already_running(void)
{
    int     fd;
    char    buf[16];

    fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE);
    if( fd < 0 )
    {
        printf("can't open %s: %s\n", LOCKFILE, strerror(errno));
        exit(1);
    }
    if( lockf(fd, F_TLOCK, 0) < 0 )
    {
        if( errno == EACCES || errno == EAGAIN )
        {
            close(fd);
            return(1);
        }
        printf("can't lock %s: %s\n", LOCKFILE, strerror(errno));
        exit(1);
    }

    ftruncate(fd, 0);
    sprintf(buf, "%ld", (long)getpid());
    write(fd, buf, strlen(buf) + 1);

    return(0);
}

int main(void)
{
    if( already_running() )
    {
        printf("already running ...\n");
        exit(0);
    }

    printf("ok\n");
    sleep(100);
}


4、守护进程的惯例

系统的守护进程在收到 SIGHUP 信号后,会重新读取配置文件
 
5、 客户机 / 服务器模型
守护进程通常充当一个服务器,等待客户端请求,并处理
后续章节会看到更多的双向通信的示例:
客户端发送请求,服务器处理并且,并发送响应结果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值