5.1 概念
(1)什么是守护进程
Daemon(守护进程)是运行在后台的一种特殊进程。**它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。**它不需要用户输入就能运行而且提供某种服务,不是对整个系统就是对某个用户程序提供服务。Linux系统的大多数服务器就是通过守护进程实现的。
(2)为什么需要守护进程
守护进程是脱离于终端并且在后台运行的进程。守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的终端信息所打断。
(3)守护进程实例
常见的守护进程包括系统日志进程syslogd、 web服务器httpd、邮件服务器sendmail和数据库服务器mysqld等。
5.2 模型
(1)守护进程编程步骤
a.创建子进程,父进程退出,一切工作在子进程中执行,形式上脱离了控制终端 b.在子进程中创建新的会话(会话后面章节会提到),使子进程完全独立出来,脱离控制 c.改变当前目录为根目录,防止占用其他可卸载的文件系统 d.重设文件权限掩码,防止继承的文件创建屏蔽字拒绝某些权限,增加守护进程的灵活性 e.关闭文件描述符 f.守护进程退出处理
代码模型:
代码语言:javascript复制#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
static bool flag = true;
void create_daemon();
void handler(int);
int main()
{
time_t t;
int fd;
create_daemon(); //进
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
// 函数执行开始
if(sigaction(SIGQUIT, &act, NULL))
{
printf("sigaction error.n");
exit(0);
}
while(flag)
{
fd = open("/home/mick/daemon.log", O_WRONLY | O_CREAT | O_APPEND, 0644);
if(fd == -1)
{
printf("open errorn");
}
t = time(0);
char *buf = asctime(localtime(&t));
write(fd, buf, strlen(buf));
close(fd);
sleep(60);
}
return 0;
}
void handler(int sig)
{
printf("I got a signal %dnI'm quitting.n", sig);
flag = false;
}
void create_daemon()
{
pid_t pid;
pid = fork(); //创建子进程
if(pid == -1)
{
printf("fork errorn");
exit(1);
}
else if(pid) //关闭父进程
{
exit(0);
}
if(-1 == setsid()) //在子进程中创建新的会话
{
printf("setsid errorn");
exit(1);
}
pid = fork(); //再次分离,更加稳定
if(pid == -1)
{
printf("fork errorn");
exit(1);
}
else if(pid)
{
exit(0);
}
chdir("/"); //改变当前目录为根目录
int i;
for(i = 0; i < 3; i)
{
close(i); //关闭原始三个流
//反正也失去了控制终端,再留着这三个也没意义
}
umask(0); //重设文件掩码
return;
}
注意守护进程一般需要在 root 权限下运行。
通过
ps -ef | grep ‘daemon’
如果想退出守护进程,kill -9 就好
其实,上面那套还有更直接的,直接通过库函数来创建守护进程:
代码语言:javascript复制#include <unistd.h>
int daemon(int nochdir, int noclose);
代码语言:javascript复制然后这个是官方解释,反正我看得懂 If nochdir is zero, daemon() changes the process’s current working directory to the root directory ("/"); otherwise, the current working directory is left unchanged.
If noclose is zero, daemon() redirects standard input, standard
output and standard error to /dev/null; otherwise, no changes are
made to these file descriptors.
然后我们对上面那串代码简化一下:
代码语言:javascript复制#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
static bool flag = true;
void handler(int);
int main()
{
time_t t;
int fd;
if(-1 == daemon(0, 0))
{
printf("daemon errorn");
exit(1);
}
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if(sigaction(SIGQUIT, &act, NULL))
{
printf("sigaction error.n");
exit(0);
}
while(flag)
{
fd = open("/home/mick/daemon.log", O_WRONLY | O_CREAT | O_APPEND, 0644);
if(fd == -1)
{
printf("open errorn");
}
t = time(0);
char *buf = asctime(localtime(&t));
write(fd, buf, strlen(buf));
close(fd);
sleep(60);
}
return 0;
}
void handler(int sig)
{
printf("I got a signal %dnI'm quitting.n", sig);
flag = false;
}
其实就是用库函数替换掉我们自己的函数。