`
brxonline
  • 浏览: 64250 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

UNIX编程(13)-守护进程

    博客分类:
  • C
 
阅读更多

1.守护进程的编程规则

1)用umask将文件模式创建屏蔽字设置为0

2)调用fork,然后使父进程退出

3)调用setsid创建一个新会话

4)将当前工作目录更改为根目录

5)关闭不再需要的的文件描述符

6)某些守护进程打开/dev/null使其具有文件描述符0,1,2,

例:初始化一个守护进程

 

 

#include "apue.h"
#include <syslog.h>
#include <fcntl.h>
#include <sys/resource.h>

void
daemonize(const char *cmd)
{
    int                 i, fd0, fd1, fd2;
    pid_t               pid;
    struct rlimit       rl;
    struct sigaction    sa;
    /*
     * Clear file creation mask.
     */
    umask(0);

    /*
     * Get maximum number of file descriptors.
     */
    if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
        err_quit("%s: can't get file limit", cmd);

    /*
     * Become a session leader to lose controlling TTY.
     */
    if ((pid = fork()) < 0)
        err_quit("%s: can't fork", cmd);
    else if (pid != 0) /* parent */
        exit(0);
    setsid();

    /*
     * Ensure future opens won't allocate controlling TTYs.
     */
    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");
    if ((pid = fork()) < 0)
        err_quit("%s: can't fork", cmd);
    else if (pid != 0) /* parent */
        exit(0);

    /*
     * Change the current working directory to the root so
     * we won't prevent file systems from being unmounted.
     */
    if (chdir("/") < 0)
        err_quit("%s: can't change directory to /");

    /*
     * Close all open file descriptors.
     */
    if (rl.rlim_max == RLIM_INFINITY)
        rl.rlim_max = 1024;
    for (i = 0; i < rl.rlim_max; i++)
        close(i);

    /*
     * Attach file descriptors 0, 1, and 2 to /dev/null.
     */
    fd0 = open("/dev/null", O_RDWR);
    fd1 = dup(0);
    fd2 = dup(0);

    /*
     * Initialize the log file.
     */
    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);
    }
}


2.出错记录

使用syslog设施产生日志

有三种方法产生日志信息:

1)内核调用log函数

2)调用syslog函数以产生日志消息

3)用网络程序发送到其他主机的514端口

 

syslogd守护进程读取三种格式的日志信息,此守护进程在启动时读一个配置文件,/etc/syslog.conf,该文件决定了不同种类的消息送向何处。

 

#include <syslog.h>

void openlog(const char *ident, int option, int
facility);

void syslog(int priority, const char *format, ...);

void closelog(void);

int setlogmask(int maskpri);

 

Returns: previous log priority mask value

 

3.单实例守护进程

 

使用文件和记录锁保证只运行守护进程的一个副本

#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <syslog.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>

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

extern int lockfile(int);

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

    fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE);
    if (fd < 0) {
        syslog(LOG_ERR, "can't open %s: %s", LOCKFILE, strerror(errno));
        exit(1);
    }
    if (lockfile(fd) < 0) {
        if (errno == EACCES || errno == EAGAIN) {
            close(fd);
            return(1);
        }
        syslog(LOG_ERR, "can't lock %s: %s", LOCKFILE, strerror(errno));
        exit(1);
    }
    ftruncate(fd, 0);
    sprintf(buf, "%ld", (long)getpid());
    write(fd, buf, strlen(buf)+1);
    return(0);
}


 4.守护进程的惯例

例:守护进程重新读配置文件

#include "apue.h"
#include <pthread.h>
#include <syslog.h>

sigset_t    mask;

extern int already_running(void);

void
reread(void)
{
    /* ... */
}

void *
thr_fn(void *arg)
{
    int err, signo;

    for (;;) {
        err = sigwait(&mask, &signo);
        if (err != 0) {
            syslog(LOG_ERR, "sigwait failed");
            exit(1);
        }

        switch (signo) {
        case SIGHUP:
            syslog(LOG_INFO, "Re-reading configuration file");
            reread();
            break;

        case SIGTERM:
            syslog(LOG_INFO, "got SIGTERM; exiting");
            exit(0);

        default:
            syslog(LOG_INFO, "unexpected signal %d\n", signo);
        }
    }
    return(0);
}

int
main(int argc, char *argv[])
{
    int                 err;
    pthread_t           tid;
    char                *cmd;
    struct sigaction    sa;

    if ((cmd = strrchr(argv[0], '/')) == NULL)
        cmd = argv[0];
    else
        cmd++;

    /*
     * Become a daemon.
     */
    daemonize(cmd);

    /*
     * Make sure only one copy of the daemon is running.
     */
    if (already_running()) {
        syslog(LOG_ERR, "daemon already running");
        exit(1);
    }

    /*
     * Restore SIGHUP default and block all signals.
     */
    sa.sa_handler = SIG_DFL;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGHUP, &sa, NULL) < 0)
        err_quit("%s: can't restore SIGHUP default");
    sigfillset(&mask);
    if ((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0)
        err_exit(err, "SIG_BLOCK error");

    /*
     * Create a thread to handle SIGHUP and SIGTERM.
     */
    err = pthread_create(&tid, NULL, thr_fn, 0);
    if (err != 0)
        err_exit(err, "can't create thread");
    /*
     * Proceed with the rest of the daemon.
     */
    /* ... */
    exit(0);
}

 

另外一种实现

 

#include "apue.h"
#include <syslog.h>
#include <errno.h>

extern int lockfile(int);
extern int already_running(void);

void
reread(void)
{
    /* ... */
}

void
sigterm(int signo)
{
    syslog(LOG_INFO, "got SIGTERM; exiting");
    exit(0);
}

void
sighup(int signo)
{
    syslog(LOG_INFO, "Re-reading configuration file");
    reread();
}
int
main(int argc, char *argv[])
{
    char                *cmd;
    struct sigaction    sa;
    if ((cmd = strrchr(argv[0], '/')) == NULL)
        cmd = argv[0];
    else
        cmd++;

    /*
     * Become a daemon.
     */
    daemonize(cmd);

    /*
     * Make sure only one copy of the daemon is running.
     */
    if (already_running()) {
        syslog(LOG_ERR, "daemon already running");
        exit(1);
    }

    /*
     * Handle signals of interest.
     */
    sa.sa_handler = sigterm;
    sigemptyset(&sa.sa_mask);
    sigaddset(&sa.sa_mask, SIGHUP);
    sa.sa_flags = 0;
    if (sigaction(SIGTERM, &sa, NULL) < 0) {
        syslog(LOG_ERR, "can't catch SIGTERM: %s", strerror(errno));
        exit(1);
    }
    sa.sa_handler = sighup;
    sigemptyset(&sa.sa_mask);
    sigaddset(&sa.sa_mask, SIGTERM);
    sa.sa_flags = 0;
    if (sigaction(SIGHUP, &sa, NULL) < 0) {
        syslog(LOG_ERR, "can't catch SIGHUP: %s", strerror(errno));
        exit(1);
    }

    /*
     * Proceed with the rest of the daemon.
     */
    /* ... */
    exit(0);
}

 

分享到:
评论

相关推荐

    Python-守护进程管理基类提供守护进程创建及终止日志记录子进程管理

    在Python编程中,守护进程(Daemon)是一种特殊类型的后台进程,通常用于运行长期存在的服务,如Web服务器或数据库服务器。为了有效地管理和控制这些守护进程,开发者通常会编写一个基类来处理守护进程的启动、停止...

    UNIX网络编程 第2卷 进程间通信.pdf(带书签)

    第13章详细讲解了守护进程和inetd超级服务器的构建方法,以及它们在网络服务中的重要作用。第16章到第19章则分别介绍了非阻塞I/O、ioctl操作、路由套接口和密钥管理套接口等高级编程技术。第20章到第25章则深入讨论...

    Linux编程接口 - Linux和UNIX系统编程手册

    - **系统管理员与高级用户**:希望深入了解Linux/UNIX编程接口及系统软件实现原理的人员。 #### 三、核心知识点概览 ##### 1. 标准兼容性与可移植性 - **POSIX标准**:本书重点关注Linux编程接口的同时,也非常...

    Linux守护进程的编程方法.pdf

    尽管不同Unix环境下守护进程的具体实现有所不同,但是它们的核心编程原则是一致的,即满足守护进程的基本特性。下面是针对Linux环境下守护进程编程的一些关键步骤: 1. **在后台运行**: - 为了确保守护进程不会挂...

    UNIX网络编程 第2卷 进程间通信 带完整书签

    UNIX网络编程 第2卷 进程间通信 ...第13章 守护进程和inetd超级服务器? 第14章 高级I/O函数 第15章 Unix域协议 第16章 非阻塞I/O 第17章 ioctl操作 第18章 路由套接口 第19章 密钥管理套接口? -------

    UNIX网络编程卷2进程间通信

    9. **守护进程(Daemons)**:UNIX系统中的后台服务进程,通常用于提供持续的服务。书中会介绍如何创建和管理守护进程。 10. **高级主题**:包括异步I/O、实时信号、线程间通信等,这些内容为开发者提供了更强大的...

    UNIX网络编程 卷2:进程间通信

     9.7 启动一个守护进程的唯一副本 170  9.8 文件作锁用 171  9.9 NFS上锁 173  9.10 小结 173  习题 174  第10章 Posix信号量 175  10.1 概述 175  10.2 sem_open、sem_close和sem_  unlink函数 179  10.3...

    守护进程,背靠背c++实现

    守护进程在Unix/Linux系统中是非常常见的一种进程类型。它们通过脱离控制终端(detaching from the controlling terminal)和会话(session)来实现后台运行。首先,守护进程会关闭所有标准输入、输出和错误流,避免...

    unix下socket编程

    本节我们将深入探讨Unix下的Socket编程,涵盖守护进程的编写、服务器与客户端的交互、高级套接字函数以及学习网络编程的方法。 1. **守护进程(Daemon)**: - 守护进程是一种在后台运行且无控制终端的进程,常用于...

    守护进程实例(很实用的编程技巧)

    守护进程在IT行业中,特别是在系统编程和服务器管理中扮演着重要的角色。它们是后台运行的程序,不与终端或控制台交互,独立于用户会话存在,通常用于提供持续的服务或者监控系统的特定状态。本实例将带你深入理解...

    c#实现的守护进程,包含代码

    在Unix/Linux系统中,我们常看到各种守护进程,而在Windows系统中,我们可以用相似的概念来理解,比如服务(Service)。在C#编程语言中,可以利用.NET Framework或.NET Core提供的功能创建Windows服务,实现类似守护...

    UNIX网络编程第1卷(1-19章)

    在高级网络编程技术方面,作者介绍了守护进程和inetd超级服务器的设计与实现,以及Unix域协议的使用。非阻塞I/O、ioctl操作和路由器接口等内容也是书中讨论的重点。广播和多播技术的讲解使得读者能够构建出支持一对...

    Linux与unix shell编程指南-下半部分

    高级话题可能包括信号处理、进程间通信(IPC)、守护进程的创建,甚至可能涉及bash扩展和自定义Shell功能。 总而言之,《Linux与Unix Shell编程指南》下半部分将带领读者从基础Shell编程逐渐过渡到高级领域,通过...

    java实现守护进程,有单独的监听进程, 两个或多个进程,两个或多个jvm

    在Java编程环境中,实现守护进程(Daemon)以及创建多个进程和JVM是非常常见的需求,特别是在构建分布式系统或者需要持续后台运行的服务时。本篇将详细阐述如何使用Java来实现这些功能。 守护进程通常是一个在后台...

    UNIX环境高级编程

    书中还单独章节讲解了守护进程的编程规则、高级I/O技术、终端I/O、伪终端、数据库函数库以及与网络打印机通信等内容。每一部分都配有相应的程序实例和源代码,供读者参考和实践。 此外,书中还包含了附录A的函数...

    python编写守护进程实现当python进程被杀后重启进程的源代码

    在Python编程中,守护进程(Daemon)是一种特殊类型的后台进程,它不依附于终端,且能在系统启动时启动,并在系统关闭时终止。守护进程常用于提供持续的服务,例如Web服务器、数据库服务等。本篇文章将深入探讨如何...

    unix高级环境编程-第三版-图书-源代码

    书中除了介绍UNIX文件和目录、标准I/O库、系统数据文件和信息、进程环境、进程控制、进程关系、信号、线程、线程控制、守护进程、各种I/O、进程间通信、网络IPC、伪终端等方面的内容,还在此基础上介绍了多个应用...

Global site tag (gtag.js) - Google Analytics