简介
守护线程在系统启动时运行,在系统终止时退出,没有控制终端,只在后台作为一个服务默默运行
编写规则
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
#include
#include
#include
#include
#include
#include
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
单例模式
单例模式: 一个软件在系统只能运行一个实例, 不能同时运行两个或多个
方法: 创建一个文件并加锁, 第一个实例运行时没问题, 第二实例运行时会因为对文件加锁失败而退出
#include
#include
#include
#include
#include
#include
#include
#include
#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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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);
}