守护进程

简介

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

编写规则

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);
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,326评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,228评论 1 304
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,979评论 0 252
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,489评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,894评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,900评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,075评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,803评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,565评论 1 249
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,778评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,255评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,582评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,254评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,151评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,952评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,035评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,839评论 2 277

推荐阅读更多精彩内容