Linux下的守护进程

守护进程也称精灵进程(Daemon),是运行在后台的一种特殊进程。它独立于控制终端并

且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程。

Linux的大多数服务器就是用守护进程实现的。比如,Internet服务器inetd,Web服务器httpd

等。同时,守护进程完成许多系统任务。比如,作业规划进程crond等。

Linux系统启动时会启动很多系统服务进程,这些系统服 务进程没有控制终端,不能直接和用

户交互。其它进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但系统

服务进程不受用户登录注销的影响,它们一直在运行着。这种进程有一个名称叫守护进程

(Daemon)。

守护进程的特点有:(1)自成一个会话,即会话id是守护进程的pid,SID==PID

                                    (2)自成一个进程组,即组长id是守护进程的pid

                                    (3)在成为守护进程之后,与控制终端失去了联系

凡是TPGID一栏写着-1的都是没有控制终端的进程,也就是守护进程。守护进程通常采用以d结尾的名字,表示Daemon。


创建守护进程的步骤:

                                    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一次

  1 #include<stdio.h>
  2 #include<signal.h>
  3 #include<unistd.h>
  4 #include<stdlib.h>
  5 void mydaemon()
  6 {
  7     umask(0);            //设置文件屏蔽字
  8     if(fork()>0)         //使父进程退出,子进程变成孤儿进程
  9     {
 10         exit(0);
 11     }
 12     setsid();           //使子进程自成一个新的会话
 13     chdir("/");         //将子进程改为根目录下
 14     close(0);
 15     close(1);           //关闭文件描述符
 16     close(2);
 17     signal(SIGCHLD,SIG_IGN);
 18 }
 19 
 20 int main()
 21 {
 22     mydaemon();
 23     while(1);
 24 }

运行./mydaemon后,进入根目录下使用ps axj命令找到守护进程 mydaemon的PID。  


进入根目录下的/proc,/proc将内存中的进程信息以及软硬件信息以文件系统形式呈现出来。

在/proc下找到守护进程的PID,cd  PID可以看到守护进程的信息 。 


cwd-->/  表示当前工作目录是根目录。

fd   是守护进程的文件描述符表 ,在这个程序中为空,可以选择不关闭 文件描述符,则fd不为空。 


  5 void mydaemon()
  6 {
  7     umask(0);
  8     if(fork()>0)
  9     {
 10         exit(0);
 11     }
 12     setsid();
 13 //  chdir("/");
 14     close(0);
 15 //  close(1);
 16 //  close(2);
 17     signal(SIGCHLD,SIG_IGN);
 18 }
将程序进行上述改变,进入守护进程后可以看见 不同的信息   -----5 6


我们也可以直接调用系统提供函数   int  daemon (int nochdir,  int  noclose)

参数有两种形式     (1)缺省:改变

                                 (2)非缺省:不改变

当调用daemon(0,0)时,工作目录为根目录,fd为空(/dev/null中的信息会被丢弃)



当调用daemon(1,1)时,工作目录和文件描述符都不改变



(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);
}
}
 1 、第一次fork的作用是让shell 认为本条命令 已经终止,不用挂在终端输入上。还有一个作用是为后面setsid服务。setsid的调用者不能是进程组组长(group leader). 此时父进程是进程组组长。
    
    2 、setsid() 是本函数最重要的一个调用。它完成了daemon函数想要做的大部分事情。调用完整个函数。子进程是会话组长(sid==pid),也是进程组组长 (pgid == pid),并且脱离了原来控制终端。到了这一步,基本上不管控制终端如何怎么样。新的进程都不会收到那些信号。
 
    3  、经过前面2个步骤,基本想要做的都做了。第2次fork不是必须的。也看到很多开源服务没有fork第二次。fork第二次主要目的是。防止进程再次 打开一个控制终端。因为打开一个控制终端的前台条件是该进程必须是会话组长。再fork一次,子进程ID != sid(sid是进程父进程的sid)。所以也无法打开新的控制终端。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值