守护进程也称精灵进程(Daemon),是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。
守护进程的特点有:(1)自成一个会话,即会话id是守护进程的pid,SID==PID
(2)自成一个进程组,即组长id是守护进程的pid
(3)在成为守护进程之后,与控制终端失去了联系
创建守护进程的步骤:
1. 调用umask将文件模式创建屏蔽字设为0
2. 调用fork,父进程退出(exit)。原因:1)如果该守护进程是作为一条简单的shell命令
启动的,那么父进程终止使得shell认为该命令已经执行完毕。2)保证子进程不是一个
进程组的组长进程。
3. 调用setsid创建一个新会话。setsid会导致:1)调用进程成为新会话的首进程。 2)调⽤用
进程成为一个进程组的组长进程 。3)调用进程没有控制终端。(再次fork一次,保证
daemon进程,之后不会打开tty设备)
4. 将当前工作目录更改为根目录。
5. 关闭不在需要的文件描述符。
6. 其他:忽略SIGCHLD信号。
下面编程实现守护进程:
1.一次fork()
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
void mydaemon()
{
umask(0); //<span style="font-family: Arial, Helvetica, sans-serif;">设置文件屏蔽字</span>
if(fork()>0) //使父进程退出,子进程变成孤儿进程
{
exit(0);
}
setsid(); //使子进程自成一个新的会话
chdir("/"); //将子进程改为根目录下
close(0);
close(1); //关闭文件描述符
close(2);
signal(SIGCHLD,SIG_IGN);
}
int main()
{
mydaemon();
while(1); }
运行./mydaemon后,进入根目录下使用ps axj命令找到守护进程 mydaemon的PID。
进入根目录下的/proc,/proc将内存中的进程信息以及软硬件信息以文件系统形式呈现出来。
在/proc下找到守护进程的PID,cd PID可以看到守护进程的信息
cwd-->/ 表示当前工作目录是根目录。
fd 是守护进程的文件描述符表 ,在这个程序中为空,可以选择不关闭 文件描述符,则fd不为空。
2.两次fork()
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
void creat_daemon(void)
{
int i;
int fd0;
pid_t pid;
struct sigaction sa;
umask(0); //设置文件掩码为0
if( (pid = fork()) < 0 ){
}else if (pid != 0){
exit(0); //终止父进程
}
setsid(); //设置新会话
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if( sigaction(SIGCHLD, &sa, NULL ) < 0 ){ // 注册子进程退出忽略信号
return;
}
if( (pid = fork())<0){ //再次fork,终止父进程,保持子进程不是话首进程,从而保证后续
不会在和其他终端关联
printf("fork error!\n");
return;
}else if( pid != 0){
exit(0);
}
if( chdir("/") < 0 ){//更改工作目录到根
printf("child dir error\n");
return;
}
close(0);
fd0 = open("/dev/null", O_RDWR); // 关闭标准输入,重定向所有标准(输入输出错误)
到/dev/null
dup2(fd0, 1);
dup2(fd0, 2);
}
int main()
{
creat_daemon();
while(1)
{
sleep(1);
}
}
我们也可以直接调用系统提供函数 int daemon (int nochdir, int noclose)
参数有两种形式 (1)缺省:改变
(2)非缺省:不改变
当调用daemon(0,0)时,工作目录为根目录,fd为空(/dev/null中的信息会被丢弃)
当调用daemon(1,1)时,工作目录和文件描述符都不改变