守护进程

编写简单守护进程

(1)任何一个进程都可以将自己变成守护进程。
(2)create_daemon函数要素

  • 子进程等待父进程退出
  • 子进程使用setsid创建新的会话期,脱离控制台
  • 调用chdir将当前工作目录设置为/
  • umask设置为0以取消任何文件权限屏蔽
  • 关闭所有文件描述符
  • 将0、1、2定位到/dev/null

最初的daemon_2016-10-14.c

#include 
#include 
#include 

void create_daemon(void);

int main(void)
{
    create_daemon();
    while(1){
        printf("I am running.\n");
        sleep(1);
    }
    return 0;
}

//函数作用就是把调用该函数的进程变成一个守护进程
void create_daemon(void)
{

}

执行a.out后,屏幕输出”I am running.”。
守护进程_第1张图片
在执行a.out的同时,ps -ajx后,可以发现进程2536。但在停止执行a.out后,进程2536也没有了。
这里写图片描述

现在开始写create_daemon()函数。

//函数作用就是把调用该函数的进程变成一个守护进程
void create_daemon(void)
{
    pid_t pid;
    if((pid = fork()) < 0)
    {
        perror("fork");
        exit(-1);
    }
    else if(pid > 0)
    {
        /* 父进程退出 */
        exit(0);
    }
    /* 子进程 */
    /* setsid将当前进程设置为一个新的会话期session */
    /* 目的就是让当前进程脱离控制台 */
    pid = setsid();
    if(pid < 0)
    {
        perror("setsid");
        exit(-1);
    }

    /* 将当前进程的工作目录设置为根目录 */
    chdir("/");

    /* umask设置为0,确保将来进程有最大打文件权限 */
    umask(0);

    /* 关闭所有文件描述符号 */
    /* 先要获取当前系统中所允许打开的最大文件数目 */
    int i;
    int cnt = sysconf(_SC_OPEN_MAX);
    for(i = 0; i < cnt; i++)
    {
        close(i);
    }

    /* 把标准输入、标准输出、标准错误输出定位到/dev/null */
    open("/dev/null", O_RDWR);
    open("/dev/null", O_RDWR);
    open("/dev/null", O_RDWR);
}

执行a.out,但发现并未输出。
这里写图片描述
但是ps -ajx还是可以看到a.out确实在执行。进程5291。
这里写图片描述
现在a.out就已经是守护进程了,此时就算我把执行a.out的终端关掉,但是ps -ajx还是能看见a.out进程,要关闭进程只能kill -9 进程号

使用syslog来记录调试信息

因为已经将标准输入、标准输出、标准错误输出定向到/dev/null,所以守护进程不能向控制台输出信息,而且守护进程已经脱离了控制台。那么守护进程如何向用户输出信息?我们可以使用syslog来记录调试信息。

syslog相关函数

#include 

void openlog(const char *ident, int option, int facility);
/* syslog记录一条信息 */
void syslog(int priority, const char *format, ...);
void closelog(void);

参数

ident是识别字符串,一般设置为当前应用程序的名字。

option:

  • LOG_CONS 如果出错输出到控制台,如果没有输出到日志信息。
  • LOG_PID 记录到日志信息的每条信息包含当前进程pid,以此区分进程(fork的进程ident都相同,用pid可以区分父子进程)。

facility可以理解为日志的来源或设备或选择条件,目前常用的facility有以下几种:

  • LOG_AUTH (auth): 身份验证相关的(登录时)
  • LOG_CRON(cron): 进程或应用调度相关的
  • LOG_DAEMON(daemon): 守护进程相关的(内部服务器)
  • LOG_KERN(kernel): 内核相关的
  • LOG_MAIL(mail): 内部邮件服务器相关的
  • LOG_SYSLOG(syslog): syslog 守护进程本身相关的
  • LOG_LPR(lpr): 打印服务相关的
  • LOG_USER (user):用户相关的
  • LOG_LOCAL0 through LOG_LOCAL7(local0 - local7): 用户自定义使用的

priority(log level)日志优先级的级别,一般分为以下几种级别(从低到高:

  • LOG_DEBUG:(debug ) 程序或系统的调试信息
  • LOG_INFO:(info) 一般信息
  • LOG_NOTICE :(notice) 不影响正常的功能,需要提醒用户的重要事件
  • LOG_WARNING:(warning/warn) 可能影响系统功能,需要提醒用户的重要事件
  • LOG_ERR:( err/error) 错误信息
  • LOG_CRIT:(crit) 比较严重的
  • LOG_ALERT :(alert) 必须马上处理的
  • LOG_EMERG:(emerg/canic) 会导致系统不可用的

实战

#include 
#include 
#include 
int main(void)
{
    openlog("syslogTest.out", LOG_PID| LOG_CONS, LOG_USER);
    syslog(LOG_INFO, "this is my log info");
    syslog(LOG_INFO, "this is another log info");
    closelog();
    return 0;
}

这里写图片描述
cat /var/log/syslog
这里写图片描述

syslog的工作原理

(1)操作系统中有一个守护进程syslogd(开机运行,关机时才结束),这个守护进程syslogd负责进行日志文件的写入和维护。
(2)syslogd是独立于我们任意一个进程运行的。我们当前进程和syslogd进程本来是没有任何关系的,但是我们当前进程可以同通过调用openlog打开一个和syslogd相连接的通道,然后通过syslog向syslogd发消息,然后由syslogd来将其写入到日志文件系统中。
(3)syslogd其实就是一个日志文件系统的服务器进程,提供日志服务。任何需要写入日志的进程都可以通过openlog/syslog/closelog这三个函数来利用syslogd提供的日志服务。这就是操作系统的服务式的设计。

你可能感兴趣的:(linux系统编程)