1、守护进程介绍:

守护进程(Daemon)也称为精灵进程,是运行在后台的一种特殊进程,它独立于控制终端并且周期性 地执行某种任务或等待处理某些事情的发生,主要表现为以下两个特点:

长期运行 。守护进程是一种生存期很长的一种进程,它们一般在系统启动时开始运行,除非强行终

止,否则直到系统关机都会保持运行。与守护进程相比,普通进程都是在用户登录或运行程序时创

建,在运行结束或用户注销时终止,但守护进程不受用户登录注销的影响,它们将会一直运行着、

直到系统关机。

与控制终端脱离。 在 Linux 中,系统与用户交互的界面称为终端,每一个从终端开始运行的进程都

会依附于这个终端,这是上一小节给大家介绍的控制终端,也就是会话的控制终端。当控制终端被

关闭的时候,该会话就会退出,由控制终端运行的所有进程都会被终止,这使得普通进程都是和运

行该进程的终端相绑定的;但守护进程能突破这种限制,它脱离终端并且在后台运行,脱离终端的

目的是为了避免进程在运行的过程中的信息在终端显示并且进程也不会被任何终端所产生的信息

所打断。

守护进程是一种很有用的进程。 Linux 中大多数服务器就是用守护进程实现的,譬如, Internet 服务器 inetd、 Web 服务器 httpd 等。同时,守护进程完成许多系统任务,譬如作业规划进程 crond 等。守护进程 Daemon ,通常简称为 d ,一般进程名后面带有 d 就表示它是一个守护进程。

ps -ajx

TTY 一栏是问号?表示该进程没有控制终端,也就是守护进程,其中 COMMAND 一栏使用中括号 [] 括

起来的表示内核线程,这些线程是在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,通常

采用 k 开头的名字,表示 Kernel 。

系统中的后台进程,周期性的执行某些任务,或者等待某个事件的发生,不会随用户的注销而退出

特点:后台服务进程,不会显示在终端,除了关机和kill,守护进程是不会死的         独立于控制终端         周期性执行某任务         不受用户登录注销影响         守护进程一般采用以d结尾的名字(服务)

2、守护进程的编写:

1)  创建子进程、终止父进程

父进程调用 fork() 创建子进程,然后父进程使用 exit() 退出,这样做实现了下面几点。第一,如果该守护 进程是作为一条简单地 shell 命令启动,那么父进程终止会让 shell 认为这条命令已经执行完毕。第二,虽然 子进程继承了父进程的进程组ID ,但它有自己独立的进程 ID ,这保证了子进程不是一个进程组的组长进程, 这是下面将要调用 setsid 函数的先决条件!

2)  子进程调用 setsid 创建会话

这步是关键,在子进程中调用上一小节给大家介绍的 setsid() 函数创建新的会话,由于之前子进程并不 是进程组的组长进程,所以调用 setsid() 会使得子进程创建一个新的会话,子进程成为新会话的首领进程, 同样也创建了新的进程组、子进程成为组长进程,此时创建的会话将没有控制端。所以这里调用

setsid 有 三个作用:让子进程摆脱原会话的控制、让子进程摆脱原进程组的控制和让子进程摆脱原控制终端的控制。

在调用 fork 函数时,子进程继承了父进程的会话、进程组、控制终端等,虽然父进程退出了,但原先 的会话期、进程组、控制终端等并没有改变,因此,那还不是真正意义上使两者独立开来。setsid 函数能够 使子进程完全独立出来,从而脱离所有其他进程的控制。

3) 将工作目录更改为根目录

子进程是继承了父进程的当前工作目录,由于在进程运行中,当前目录所在的文件系统是不能卸载的, 这对以后使用会造成很多的麻烦。因此通常的做法是让“/ ”作为守护进程的当前目录,当然也可以指定其 它目录来作为守护进程的工作目录。

将守护进程的标准输入、标准输出以及标准错误重定向到/dev/null ,这使得守护进程的输出无处显示、 也无处从交互式用户那里接收输入。

ps -aux  ps -ajx

3、守护进程的执行流程:

        1.fork子进程,父进程退出,必须做         2.子进程创建新会话,必须做,setsid()函数         3.改变当前工作目录chdir,不是必须的,增强程序的健壮性         4.重设文件掩码              原因:子进程会继承父进程的掩码             目的:增加子进程程序操作的灵活性             umask(0);         5.关闭文件描述符,不是必须的             子进程脱离终端了,所以需要关闭标准输入,标准输出,标准错误输出             目的:释放资源         6.执行核心工作,必须的

4、

#include 
 
          
#include 
 
          
#include 
 
          
#include 
 
          
#include 
 
          
#include 
 
          
#include 
 
          
int  
           main 
           ( 
           void 
           ) 
 
          
{ 
 
          
pid_t pid 
           ; 
 
          
int  
           i 
           ; 
 
          
/*  
           创建子进程  
           */ 
 
          
pid  
           =  
           fork 
           (); 
 
          
if  
           ( 
           0  
           >  
           pid 
           ) { 
 
          
perror 
           ( 
           "fork error" 
           ); 
 
          
exit 
           (- 
           1 
           ); 
 
          
} 
 
          
else if  
           ( 
           0  
           <  
           pid 
           ) 
           // 
           父进程
 
          
exit 
           ( 
           0 
           ); 
           // 
           直接退出 
 
          
/* 
 
          
* 
           子进程 
 
          
*/ 
 
          
/* 1. 
           创建新的会话、脱离控制终端  
           */ 
 
          
if  
           ( 
           0  
           >  
           setsid 
           ()) { 
 
          
perror 
           ( 
           "setsid error" 
           ); 
 
          
exit 
           (- 
           1 
           ); 
 
          
} 
 
          
/* 2. 
           设置当前工作目录为根目录  
           */ 
 
          
if  
           ( 
           0  
           >  
           chdir 
           ( 
           "/" 
           )) { 
 
          
perror 
           ( 
           "chdir error" 
           ); 
 
          
exit 
           (- 
           1 
           ); 
 
          
} 
 
          
/* 3. 
           重设文件权限掩码  
           umask */ 
 
          
umask 
           ( 
           0 
           ); 
 
          
/* 4. 
           关闭所有文件描述符  
           */ 
 
          
for  
           ( 
           i  
           =  
           0 
           ;  
           i  
           <  
           sysconf 
           ( 
           _SC_OPEN_MAX 
           );  
           i 
           ++) 
 
          
close 
           ( 
           i 
           ); 
 
          
/* 5. 
           将文件描述符号为  
           0 
           、 
           1 
           、 
           2  
           定位到 
           /dev/null */ 
 
          
open 
           ( 
           "/dev/null" 
           ,  
           O_RDWR 
           ); 
 
          
dup 
           ( 
           0 
           ); 
 
          
dup 
           ( 
           0 
           ); 
 
          
/* 6. 
           忽略  
           SIGCHLD  
           信号  
           */ 
 
          
signal 
           ( 
           SIGCHLD 
           ,  
           SIG_IGN 
           ); 
 
          
/*  
           正式进入到守护进程  
           */ 
 
          
for  
           ( ; ; ) { 
 
          
sleep 
           ( 
           1 
           ); 
 
          
puts 
           ( 
           " 
           守护进程运行中 
           ......" 
           ); 
 
          
} 
 
          
exit 
           ( 
           0 
           ); 
 
          
}

5、守护进程终极总结

除非关机或者kill这个守护进程,否则它会一直运行。所以如果不杀死我们这个程序,那么我们这个程序就会将磁盘写满,所以我们需要杀死这个守护进程。  

守护进程 一般都是由 rc.s 启动,启动 很多服务