某些服务需要一直在后台跑。
守护进程一般是一个会话的Leader,也是一个进程组的Leader。
一个session(会话)中存在多个进程,前台进程组,后台进程组。最多只有一个前台进程组,可以没有。只有前台进程组能使用标准输入输出
。
守护进程的特点:
setsid();//创建一个会话,并设置进程组ID。
只有子进程才能创建会话,调用方会成为新的会话的leader,会成为当前新的进程组的leader,并脱离控制终端。
执行ps axj命令:
守护进程的tty为’?’,sid,pgid,pid相同。如果创建的子进程是守护进程,那么其父进程不会一直等,
所以守护进程的ppid为1。(不一定,ubuntu较新的发行版都用 upstart 代替 init 来收养孤儿进程
。)
几个进程组函数:
int setpgid(pid_t pid, pid_t pgid); //将指定pid号的进程放到pgid进程组
pid_t getpgid(pid_t pid); //返回指定pid号的进程的进程组id,为0时返回当前进程id
pid_t getpgrp(void); //返回当前进程的进程组id,POSIX.1方言
pid_t getpgrp(pid_t pid); //查看某个进程的进程组id,BSD方言
单实例守护进程:锁文件/var/run/name.pid ,记录了某些守护进程的pid。
(一些守护进程如sshd、rsyslogd,同一时间只能跑一份,利用锁文件来完成单实例守护进程的控制)
启动脚本文件:/etc/rc*…,人为将某个守护进程添加到启动项
“每个系统服务都有必要写系统日志,但我又不能让人人都写” --> 权限分隔层。
root将写系统日志的权限交给syslogd服务,所有要写系统日志的进程都将日志信息提交syslogd, 由syslogd统一地接收、写系统日志。
相关函数:
#include <syslog.h>
openlog(); //与syslog关联
syslog(); //提交
closelog();
①函数原型:void openlog(const char *ident, int option, int facility);
ident:可以是任何字段,一般是程序名字
option:一些控制标志,如LOG_PID表示每条日志信息包含PID;LOG_PERROR表示同时将error信息打印到stderr。
facility:提交日志信息的服务类型,也可以说是日志信息来源;
如LOG_DAEMON表示系统守护进程的日志,LOG_FTP表示是FTP的日志信息
②函数原型:void syslog(int priority, const char *format, …);
priority:是facility或上level的结果,level是级别,如LOG_ERR,LOG_WARNING,LOG_INFO
format:类似printf的格式,不用’\n’,因为我们只是提交信息,由syslogd服务实际写日志。
/var/log/syslog记录了系统大部分日志信息
/etc/rsyslog.conf为syslog配置文件,如约定level>LOG_INFO才往日志中写信息。
创建一个守护进程,守护进程负责不断往/tmp/out中写数字;并将程序中的错误提交系统日志。
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <syslog.h> #define FNAME "/tmp/out" static int creatdaemon(void) { int fd; pid_t pid; pid = fork(); if(pid < 0) return -1; //fork失败 if(pid > 0) { //printf("[%d]:parent exit\n",pid); exit(0); //父进程直接退出 } //printf("[%d]:child is working\n",pid); fd = open("/dev/null",O_RDWR); if(fd < 0) return -2; //open失败 //脱离控制终端,将0,1,2重定向到/dev/null dup2(fd,0); dup2(fd,1); dup2(fd,2); close(fd); setsid(); chdir("/");//守护进程一直在跑,最好就将PWD切换成根,因为根是一直存在的 return 0; } static void daemontask(void) { int i = 0; FILE *fp; fp = fopen(FNAME,"w"); if(fp == NULL) { syslog(LOG_ERR,"fopen() failed!"); exit(1); } while(1) { fprintf(fp,"%d\n", i++); fflush(fp); //文件是全缓冲,要刷新缓冲区 sleep(1); } fclose(fp); } int main(int argc, char **argv) { int ret = 0; openlog("mydaemon",LOG_PID,LOG_DAEMON);//关联syslog,想要写日志的人物为mydaemon,日志包含其 pid,日志的来源为守护进程 ret = creatdaemon(); if(ret < 0) { syslog(LOG_ERR,"creatdaemon() failed!"); if(ret == -1) syslog(LOG_ERR,"fork() failed!"); if(ret == -2) syslog(LOG_ERR,"open() failed!"); exit(1); } else syslog(LOG_INFO,"creatdaemon() success!"); daemontask(); exit(0); }
①先将文件设置为不可写:chmod u-w /tmp/out
②运行程序并检查守护进程是否创建成功
③查看系统日志文件/var/log/syslog