Daemon进程

这又是一个有趣的概念,daemon在英语中是"精灵"的意思,就像咱们常常在迪斯尼动画里见到的那些,有些会飞,有些不会,常常围着动画片的主人公转来转去,啰里啰唆地提一些忠告,时不时倒霉地撞在柱子上,有时候还会想出一些小小的花招,把主人公从敌人手中救出来,正因如此,daemon有时也被译做"守护神"。因此,daemon进程在国内也有两种译法,有些人译做"精灵进程",有些人译做"守护进程",这两种称呼的出现频率都很高。shell

与真正的daemon类似,daemon进程也习惯于把本身隐藏在人们的视线以外,默默为系统作出贡献,有时人们也把它们称做"后台服务进程"。daemon进程的寿命很长,通常来讲,从它们一被执行开始,直到整个系统关闭,它们才会退出。几乎全部的服务器程序,包括咱们熟知的Apache和wu-FTP,都用daemon进程的形式实现。不少Linux下常见的命令如inetd和ftpd,末尾的字母d就是指daemon。服务器

为何必定要使用daemon进程呢?Linux中每个系统与用户进行交流的界面称为终端(terminal),每个今后终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端(Controlling terminal),当控制终端被关闭时,相应的进程都会被自动关闭。关于这点,读者能够用X-Window中的XTerm试验一下,(每个XTerm就是一个打开的终端,)咱们能够经过键入命令启动应用程序,好比:session

$netscape动画

而后咱们关闭XTerm窗口,刚刚启动的netscape窗口也会随之一同忽然蒸发。可是daemon进程却可以突破这种限制,即便对应的终端关闭,它也能在系统中长久地存在下去,若是咱们想让某个进程长命百岁,不由于用户或终端或其余的变化而受到影响,就必须把这个进程变成一个daemon进程。命令行

若是想把本身的进程变成daemon进程,咱们必须严格按照如下步骤进行:继承

  1. 调用fork产生一个子进程,同时父进程退出。咱们全部后续工做都在子进程中完成。这样作咱们能够:
    1. 若是咱们是从命令行执行的该程序,这能够形成程序执行完毕的假象,shell会回去等待下一条命令;
    2. 刚刚经过fork产生的新进程必定不会是一个进程组的组长,这为第2步的执行提供了前提保障。

    这样作还会出现一种颇有趣的现象:因为父进程已经先于子进程退出,会形成子进程没有父进程,变成一个孤儿进程(orphan)。每当系统发现一个孤儿进程,就会自动由1号进程收养它,这样,原先的子进程就会变成1号进程的子进程。 
  2. 调用setsid系统调用。这是整个过程当中最重要的一步。setsid的介绍见附录2,它的做用是建立一个新的会话(session),并自任该会话的组长(session leader)。若是调用进程是一个进程组的组长,调用就会失败,但这已经在第1步获得了保证。调用setsid有3个做用:把当前工做目录切换到根目录。若是咱们是在一个临时加载的文件系统上执行这个进程的,好比:/mnt/floppy/,该进程的当前工做目录就会是/mnt/floppy/。在整个进程运行期间该文件系统都没法被卸下(umount),而不管咱们是否在使用这个文件系统,这会给咱们带来不少不便。解决的方法是使用chdir系统调用把当前工做目录变为根目录,应该不会有人想把根目录卸下吧。关于chdir的用法,参见附录1。 
    1. 让进程摆脱原会话的控制;
    2. 让进程摆脱原进程组的控制;
    3. 让进程摆脱原控制终端的控制;

    总之,就是让调用进程彻底独立出来,脱离全部其余进程的控制。 
  3. 固然,在这一步里,若是有特殊的须要,咱们也能够把当前工做目录换成其余的路径,好比/tmp。 
  4. 将文件权限掩码设为0。这须要调用系统调用umask,参见附录3。每一个进程都会从父进程那里继承一个文件权限掩码,当建立新文件时,这个掩码被用于设定文件的默认访问权限,屏蔽掉某些权限,如通常用户的写权限。当另外一个进程用exec调用咱们编写的daemon程序时,因为咱们不知道那个进程的文件权限掩码是什么,这样在咱们建立新文件时,就会带来一些麻烦。因此,咱们应该从新设置文件权限掩码,咱们能够设成任何咱们想要的值,但通常状况下,你们都把它设为0,这样,它就不会屏蔽用户的任何操做。 
    若是你的应用程序根本就不涉及建立新文件或是文件访问权限的设定,你也彻底能够把文件权限掩码一脚踢开,跳过这一步。
  5. 关闭全部不须要的文件。同文件权限掩码同样,咱们的新进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不被咱们的daemon进程读或写,但它们同样消耗系统资源,并且可能致使所在的文件系统没法卸下。须要指出的是,文件描述符为0、1和2的三个文件(文件描述符的概念将在下一章介绍),也就是咱们常说的输入、输出和报错这三个文件也须要被关闭。极可能很多读者会对此感到奇怪,难道咱们不须要输入输出吗?但事实是,在上面的第2步后,咱们的daemon进程已经与所属的控制终端失去了联系,咱们从终端输入的字符不可能达到daemon进程,daemon进程用常规的方法(如printf)输出的字符也不可能在咱们的终端上显示出来。因此这三个文件已经失去了存在的价值,也应该被关闭。 

下面,就然咱们亲眼看一个daemon进程的诞生:进程

/* daemon.c */资源

#include<unistd.h>terminal

#include<sys/types.h>it

#include <sys/stat.h>

#define MAXFILE 65535

main()

  pid_t pid;  int i;        

  pid=fork(); 

  if(pid<0)

  {  

    printf("error in fork\n");  

    exit(1); 

  }

  else if(pid>0)   

  /* 父进程退出 */  

  exit(0);  

 

  /* 调用setsid */        

  setsid(); 

 

  /* 切换当前目录 */        

  chdir("/"); 

 

  /* 设置文件权限掩码 */ 

  umask(0); 

 

  /* 关闭全部可能打开的不须要的文件 */ 

  for(i=0;i<MAXFILE;i++)  

  close(i); 

 

  /*到如今为止,进程已经成为一个彻底的daemon进程,你能够在这里添加任何你要daemon作的事情*/  

  for(;;)  

  sleep(10);

}

相关文章
相关标签/搜索