守护进程

作者: 陈伟志 | 来源:发表于2016-07-05 13:47 被阅读0次

简介

守护线程在系统启动时运行,在系统终止时退出,没有控制终端,只在后台作为一个服务默默运行

编写规则

1.调用umask()设置文件创建时的权限规则
2.调用fork, 然后使父进程exit
3.调用setsid创建一个新会话
4.将系统根目录设置为当前工作目录
5.关闭不再需要的文件描述符
6.将0,1,2标准输入输出重定向到/dev/null

出错记录

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

ident会被记录在日志内, 作为与其它进程记录的区分

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

priority表示等级, 如消息/警告/出错等;
第二个参数表示可以进行格式化, 所有%m字符被会被自动替换成strerror(errno)表示的字符串

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/resource.h>
 
void daemonize(const char *cmd){
    int i,fd0,fd1,fd2;
    pid_t pid;
    struct rlimit rl;
    struct sigaction sa;
 
    umask(0);
 
    if(getrlimit(RLIMIT_NOFILE,&rl) < 0){
        perror("getrlimit failed");
        exit(1);
    }
 
    if((pid=fork()) <0 ){
        perror("fork failed");
        exit(1);
    }else if(pid != 0)
        exit(0);
    setsid();
 
    sa.sa_handler=SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags=0;
    if(sigaction(SIGHUP,&sa,NULL) <0){
        perror("sigaction failed");
        exit(1);
    }
    if((pid=fork())<0){
        perror("fork failed");
        exit(1);
    }else if(pid != 0)
        exit(0);
 
    if(chdir("/")<0){
        perror("chdir error");
        exit(1);
    }
 //关闭所有打开的文件描述符, 包括stdin/stdout/stderr
    if(rl.rlim_max == RLIM_INFINITY)
        rl.rlim_max=1024;
    for(i=0;i<rl.rlim_max;i++)
        close(i);
 //由于上面已经关闭所有文件描述符, 所以新建文件描述符时会从0开始计数, 于是fd0=0,依次fd1=1,fd2=2
    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 description %d %d %d", fd0, fd1, fd2);
        exit(1);
    }
}
 
int main(){
   daemonize("io.c");
   return 0; 

单例模式

单例模式: 一个软件在系统只能运行一个实例, 不能同时运行两个或多个
方法: 创建一个文件并加锁, 第一个实例运行时没问题, 第二实例运行时会因为对文件加锁失败而退出

#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)
 
int lockfile(int fd){
    struct flock fl;
 
    fl.l_type=F_WRLCK;
    fl.l_start=0;
    fl.l_whence=SEEK_SET;
    fl.l_len=0;
    return(fcntl(fd,F_SETLK,&fl));
}
 
int already_running(){
    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;
}
 
int main(){
    int ret;
    ret=already_running();
//第二个实例会打印already running,然后退出
    if(ret == 1){
        printf("already running \n");
        exit(0);
    }
//第一个实例一直运行
    while(1){
        printf("from %ld \n",(long)getpid());
        sleep(2);
    }
    return 0;
}

单线程单例守护进程

如果守护线程的文件是锁文件, 一般存储在/var/run目录, 名称的形式多为name.pid
如果文件是配置文件, 一般存储在/etc目录, 名称的形式为name.conf
当配置文件修改后, 需手动发送sighup信号给后台进程: kill -SIGHUP xxx

#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <syslog.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/resource.h>
 
#define LOCKFILE "/var/run/daemon.pid"
#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
void daemonize(const char *cmd){ //同上
    ... 
}
 
int lockfile(int fd){ //同上
    ...
}
 
int already_running(){ //同上
   ...
}
 
void reread(){
    int fd;
    fd=open(LOCKFILE,O_RDONLY);
    if(fd<0){
        syslog(LOG_ERR,"can't open %s: %s",LOCKFILE,strerror(errno));
        exit(1);
    }
    char buf[100]={0};
    int nread;
    if((nread=read(fd,buf,100))>0)
        syslog(LOG_INFO,"file content change to %s",buf);
}
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(){
    char *cmd="daemonize test";
    daemonize(cmd);
 
    if(already_running()){
        syslog(LOG_ERR,"daemon already running");
        exit(1);
    }
 
    struct sigaction sa;
    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);
    }
 
//业务写这里
    while(1){
        sleep(5);
    }
    exit(0);
}

相关文章

  • rsync服务企业应用

    守护进程服务企业应用: 守护进程多模块功能配置 守护进程的排除功能实践 守护进程来创建备份目录 守护进程的访问控制...

  • Python多进程

    守护进程 守护进程其实就是“子进程“是否伴随主进程一起结束:守护==>伴随,即守护进程会伴随主进程的代码运行完毕后...

  • 守护进程和守护线程详解

    守护进程 什么是守护进程? 守护进程会在主进程代码运行结束的情况下,立即挂掉。 守护进程本身就是一个子进程。 主进...

  • 4.5、守护进程及信号处理实战

    1、守护进程功能的实现守护进程融入项目,解放终端。相关配置:Daemon = 1;按照守护进程的方式运行守护进程如...

  • PHP创建守护进程

    PHP 创建守护进程 执行守护进程

  • forever

    start:启动守护进程stop:停止守护进程stopall:停止所有的forever进程restart:重启守护...

  • 进程守护进程

    什么是守护进程?Linux 的大多数服务器就是用守护进程实现的,使用ps -axj可以查看守护进程: 守护进程基本...

  • redis.conf详解之daemonize

    用法 作为非守护进程运行 作为守护进程运行 注意事项: 默认情况下,Redis不作为守护进程运行。如果以守护进程运...

  • 守护进程,互斥锁,队列,生产者消费者模型

    守护进程 关于守护进程需要强调两点: 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进...

  • 开源HIDS-Wauzh功能测试

    一、Wazuh 守护进程及工具进程 守护进程 ossec-agentd https://documentation...

网友评论

    本文标题:守护进程

    本文链接:https://www.haomeiwen.com/subject/rumhjttx.html