守护进程简介:
守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程常常在系统引导装入时启动,在系统关闭时终止。Linux系统有很多守护进程,大多数服务都是通过守护进程实现的,同时,守护进程还能完成许多系统任务,例如,作业规划进程crond、打印进程lqd等(这里的结尾字母d就是Daemon的意思)。 由于在Linux中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。但是守护进程却能够突破这种限制,它从被执行开始运转,直到整个系统关闭时才退出。如果想让某个进程不因为用户或终端或其他地变化而受到影响,那么就必须把这个进程变成一个守护进程。
创建守护进程(5步):
1、创建子进程,父进程退出
首先调用fork,然后使父进程exit。这样做实现了下面几点:第一,如果该守护进程是由一条简单shell命令启动的,那么使父进程终止使得shell认为这条命令已经执行完成。第二,子进程继承了父进程的进程组ID,但具有一个新的进程ID,这就保证了子进程不是一个进程组的首进程。这对于下面就要做的setsid调用是必要的前提条件。
2、调用setsid以创建一个新的会话,并担任该会话组的组长。
调用setsid作用有三个:
(a)成为新会话期的首进程
(b)成为一个新进程组的首进程
(c)脱离控制终端
(会话组是一个或多个进程组的集合)
setsid() 函数格式:
#include <sys/types.h>
#include <unist.h>
Pid_t setsid(void)
函数成功时返回该进程组ID,出错时返回-1。
3、改变当前目录为根目录
chdir("/");
从父进程继承过来的当前工作目录可能在一个mnt的文件系统中。因为守护进程通常在系统在引导之前一直存在的,所以如果守护进程的当前工作目录在一个mnt文件系统中,那么该文件系统就不能被拆卸。
4、重设文件权限掩码
umask(0);
0是所有的权限都是打开的。
5、关闭不再需要的文件描述符
for(i=0;i<MAXFILE;i++)
close(i);
程序实例daemon.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#define MAXFILE 65535
int main()
{
pid_t pc;
int i,fd,len;
char *buf="This is a dameon\n";
len =strlen(buf);
pc=fork();
if(pc<0)
{
printf("error fork\n");
exit(1);
}
else if(pc>0)
exit(0);
setsid();
chdir("/");
umask(0);
for(i=0;i<MAXFILE;i++)
close(i);
fd=open("/tmp/daemon.log",O_CREAT|O_WRONLY|O_APPEND,0600);
/*fopen()是缓存的;open() 是非缓存的*/
while(1)
{
if(fd<0)
{
perror("open");
exit(1);
}
write(fd,buf,len+1);
sleep(5);
}
close(fd);
}
守护进程的出错处理:
由于守护进程完全脱离了控制终端,因此,不能像其他程序一样通过输出错误信息到控制台的方式来通知程序员。
通常的办法是使用syslog服务,将出错的信息输入到“/var/log/message”系统日志文件中去。
syslog是linux中的系统日志管理服务通过守护进程syslog来维护。
openlog函数用于打开系统日志服务的一个连接;
syslog函数用于向日志文件中写入消息,在这里可以规定消息的优先级、消息的输出格式等;
closelog函数用于关闭系统日志服务的连接。
(1)openlog函数
#include <syslog.h>
void openlog(char * ident,int option,int facility);
ident:要向每个消息加入的字符串,通常为程序的名称;
option参数
LOG_CONS:若日志消息不能通过发送至syslogd,则将消息写至控制台;
facility参数
(2)syslog函数
#include <syslog.h>
void syslog(int priority,char *format,...);
priority选项(消息优先级)
(3)closelog函数
#include <syslog.h>
void closelog(void);
实验代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<syslog.h>
#define MAXFILE 65535
int main()
{
pid_t pc,sid;
int i,fd,len;
char *buf="This is a daemon\n";
len =strlen(buf);
pc=fork();
if(pc<0)
{
printf("error fork\n");
exit(1);
}
else if(pc>0)
exit(0);
openlog("demo_update",LOG_PID,LOG_DAEMON);
if((sid=setsid())<0)
{
syslog(LOG_ERR,"%s\n","setsid");
exit(1);
}
if((sid=chdir("/"))<0)
{
syslog(LOG_ERR,"%s\n","chdir");
exit(1);
}
umask(0);
for(i=0;i<MAXFILE;i++)
close(i);
fd=open("/tmp/daemon.log",O_CREAT|O_WRONLY|O_APPEND,0600);
/*fopen()是缓存的;open() 是非缓存的*/
while(1)
{
if(fd<0)
{
syslog(LOG_ERR,"open");
exit(1);
}
write(fd,buf,len+1);
sleep(5);
}
close(fd);
closelog();
}
如果在/tmp目录下没有daemon.log文件时,open()函数就会返回出错。
syslog(LOG_ERR,"open");
然后我们就在/var/log/messages文件的最后一行发现:
Sep 7 06:04:00 localhost dame_update[4932]: open