一、 守护进程的概念:linux
守护进程(Daemon)是一种运行在后台的一种特殊的进程,它独立于控制终端而且周期性的执行某种任务或等待处理某些发生的事件。因为在Linux中,每一个系统与用户进行交流的界面成为终端,每个今后终端开始运行的进程都会依附于这个终端,这个终端被称为这些进程的控制终端,当控制终端被关闭的时候,相应的进程都会自动关闭。可是守护进程却能突破这种限制,它脱离于终端而且在后台运行,而且它脱离终端的目的是为了不进程在运行的过程当中的信息在任何终端中显示而且进程也不会被任何终端所产生的终端信息所打断。它从被执行的时候开始运转,知道整个系统关闭才退出(固然能够认为的杀死相应的守护进程)。若是想让某个进程不由于用户或中断或其余变化而影响,那么就必须把这个进程变成一个守护进程。shell
二、 守护进程实现的步骤:函数
(1) 建立子进程,父进程退出(使子进程成为孤儿进程):这是编写守护进程的第一步,因为守护进程是脱离终端的,所以完成第一步后就会在shell终端里形成一个程序已经运行完毕的假象。以后的全部工做在子进程中完成,而用户在shell终端里则能够执行其余命令,从而在形式上作到了与控制终端脱离。实现的语句以下:if(pid=fork()){exit(0);}是父进程就结束,而后子进程继续执行。this
(2) 在子进程中建立新的会话(脱离控制终端):编码
这步是建立守护进程中最重要的一步,虽然实现起来很简单,可是它的意义很是重要,在这里使用的是系统函数setsid()来建立一个新的会话,而且担任该会话组的组长。在这里有两个概念须要解释一下,进程组合会话期。spa
进程组:是一个或多个进程的集合。进程组有进程组ID来惟一标识。除了进程号(PID)以外,进程组ID也是一个进程的必备属性。每一个进程组都有一个组长进程,其组长进程的进程号等于进程组ID。且该进程组ID不会因组长进程的退出而受到影响。.net
会话周期:会话期是一个或者多个进程的集合。一般一个会话开始于用户的登陆,终止于用户的退出,在此期间该用户运行的全部进程都属于这个会话期。继承
Setsid()函数的相关内容:进程
(1) setsid()函数的做用:建立一个新的会话,而且担任该会话组的组长。具体做用包括:让一个进程摆脱原会话的控制,让进程摆脱原进程的控制,让进程摆脱原控制终端的控制。事件
(2) 建立守护进程要调用setsid()函数的缘由:因为建立守护进程的第一步是调用fork()函数来建立子进程,再将父进程退出。因为在调用了fork()函数的时候,子进程拷贝了父进程的会话期、进程组、控制终端等资源、虽然父进程退出了,可是会话期、进程组、控制终端等并无改变,所以,须要用setsid()韩式来时该子进程彻底独立出来,从而摆脱其余进程的控制。
(3) 改变当前目录为根目录:
使用fork()建立的子进程是继承了父进程的当前工做目录,因为在进程运行中,当前目录所在的文件系统是不能卸载的,这对之后使用会形成不少的麻烦。所以一般的作法是让“/”做为守护进程的当前目录,固然也能够指定其余的别的目录来做为守护进程的工做目录。
(4) 重设文件权限掩码:
文件权限掩码是屏蔽掉文件权限中的对应位。因为使用fork()函数新建立的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带了不少的麻烦(好比父进程中的文件没有执行文件的权限,然而在子进程中但愿执行相应的文件这个时候就会出问题)。所以在子进程中要把文件的权限掩码设置成为0,即在此时有最大的权限,这样能够大大加强该守护进程的灵活性。设置的方法是:umask(0)。
(5) 关闭文件描述符:
同文件权限码同样,用fork()函数新建的子进程会从父进程那里继承一些已经打开了的文件。这些文件被打开的文件可能永远不会被守护进程读写,若是不进行关闭的话将会浪费系统的资源,形成进程所在的文件系统没法卸下以及引发预料的错误。按照以下方法关闭它们:
for(i=0;i 关闭打开的文件描述符close(i);
(6) 守护进程的退出:
上面创建了守护进程,当用户须要外部中止守护进程运行时,每每须要使用kill命令来中止该守护进程,因此守护进程中须要编码来实现kill发出的signal信号处理,达到进程的正常退出。实现该过程的函数是signal函数:
signal(SIGTERM, sigterm_handler);
void sigterm_handler(int arg)
{
//进行相应处理的函数
}。功能是:将一个给定的函数和一个特定的信号联系起来,即在收到特定的信号的时候执行相应的函数。
三、守护进程实现的一个简单的例子:
#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(); //使子进程独立1.摆脱原会话控制 2.摆脱原进程组的控制 3.摆脱控制中端的控制 chdir("/"); //改变当前工做目录,这也是为了摆脱父进程的影响 umask(0); //重设文件权限掩码 for(i=0;i<MAXFILE;i++) //关闭文件描述符(常说的输入,输出,报错3个文件), //由于守护进程要失去了对所属的控制终端的联系,这三个文件要关闭 close(i); while(1) { if((fd=open("/tmp/dameon.txt",O_CREAT|O_WRONLY|O_APPEND,0600))<0) { printf("open file err \n"); exit(0); } write(fd,buf,len+1); close(fd); sleep(10); } }