概念:
PIG=PGID=PSID
系统日志 syslogd服务
守护进程的单例
主要函数:
setsid getpgrp getpgid getpgid setpgid fflush openlog syslog closelog
pid_t setsid(void);
创建一个新的回话 成功返回pid_t失败返回-1
获取进程组id:
pid_t getpgrp(void);//方言 pid_t getpgrp(psid_t pid);//方言 pid_t getpgid(pid_t pid);
将一个进程放到一个进程组中
int setpgid(pid_t pid,pid_t pgid);
void openlog(const char * ident,int option,int facility);
与系统日志建立关联
ident:日志每行开头字符串 比如程序名称
option:控制调用 可以有多个常用LOG_PID
factility:指的是消息类型 LOG_KERN、LOG_USER、LOG_MAIL、LOG_DAEMON、LOG_AUTH、LOG_SYSLOG、LOG_LPR、LOG_NEWS、LOG_UUCP、LOG_CRON 或 LOG_AUTHPRIV
具体man
void syslog(int priority,const char * format,...);
写日志
priority:级别
format:printf() 一样用。。
void closelog(void);
取消日志关联
规则:P374
1.根据守护进程屏蔽字段 通常是umask(0)。如果守护进程需要创建文件需要根据需要设定
2.fork子进程,父进程exit
3.调用setsid创建一个新的会话
4.处理信号
5.改变当前工作目录为根目录chdir("/")
6.关闭不需要的文件描述符getrlimit获取文件描述符的最大值
7.重定向将0、1、2这三个文件描述符号 open("/dev/null").由于守护进程脱离了控制终端所以是不关心设备的。dup2(fd,012)
8.编写日志 openlog
demo:
static int daemon_exit(int s)
{
//closelog();
//fclose(fp);
exit(0);
//atexit()可以被调用
}
static int daemonize(void) { int fd; pid_t pid; openlog("mydaemon",LOG_PID,LOG_DAEMON); pid=fork(); if(pid<0) { syslog(LOG_ERR,"fork() %s",strerror(errno)); return -1; } if(pid>0) exit(0);
struct sigaction sa; sa.sa_handler = daemon_exit;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask,SIGINT);
sigaddset(&sa.sa_mask,SIGTERM);
sigaddset(&sa.sa_mask,SIGQUIT);
sa.sa_flags = 0;
sigaction(SIGINT,&sa,NULL);
sigaction(SIGTERM,&sa,NULL);
sigaction(SIGQUIT,&sa,NULL); fd=open("/dev/null",O_RDWR); if(fd<0) { syslog(LOG_WARNING,"open() %s",strerror(errno)); } else { dup2(fd,0); dup2(fd,1); dup2(fd,2); if(fd>2) close(); } /* //关闭所有文件描述符 如果有必要的话 有可能在一个程序里 子进程 变身为守护进程后 需要父进程打开的文件描述符 所以一下不合适 比如网路 struct rlimit r1; if(getrlimit(RLIMIT_NOFILE,&r1)<0) syslog(LOG_ERR,"getrlimit() %s",strerror(errno)); for(i=0;i<r1.rlim_max;i++) { close(i); } */ setsid(); chdir("/"); umask(0); return 0; }