Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1132242
  • 博文数量: 300
  • 博客积分: 37
  • 博客等级: 民兵
  • 技术积分: 772
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-26 04:46
文章分类
文章存档

2017年(4)

2016年(7)

2015年(19)

2014年(72)

2013年(71)

2012年(127)

分类:

2012-09-24 22:19:21

原文地址:深入理解 Daemon 作者:cspyb_cu

Daemon进程通常译作“守护进程”,有时也把它们称作“后台服务进程”。很多Linux下常见的命令如inetd和ftpd,末尾的字母d就是指daemon。
      在Linux中,每一个系统与用户进行交流的界面称为终端(terminal),每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为
这些进程的控制终端(Controlling terminal),当控制终端被关闭时,相应的进程都会被自动关闭。但是daemon进程却能够突破这种限制,
daemon进程从被执行开始,直到整个系统关闭才会退出。如果想让某个进程不因为用户或终端或其他的变化而受到影响,就必须把这个进程变成一个daemon进程。
      如果要将自己的进程变成daemon进程,必须严格按照以下步骤进行:

(1) 调用fork产生一个子进程,同时父进程退出。所有后续工作都在子进程中完成。这样,如果是从命令行执行的该程序,这可以造成程序执
      行完毕的假象,shell会回去等待下一条命令;而刚刚通过fork产生的新进程一定不会是一个进程组的组长,这为第2步的执行提供了前提保障。
      这样还会出现一种很有趣的现象:由于父进程已经先于子进程退出,会造成子进程没有父进程,变成一个孤儿进程(orphan)。每当系统发现
      一个孤儿进程,就会自动由1号进程收养它,这样,原先的子进程就会变成1号进程的子进程。
     (2)调用setsid系统调用。这是整个过程中最重要的一步。setsid的介绍见附录2,它的作用是创建一个新的会话(session),并自任该
      会话的组长(session leader)。如果调用进程是一个进程组的组长,调用就会失败,但这已经在第1步得到了保证。调用setsid有下面的
3个作用:一是让进程摆脱原会话的控制;二是让进程摆脱原进程组的控制;三是让进程摆脱原控制终端的控制;总之,就是让调用进程完全
独立出来,脱离所有其他进程的控制。
      把当前工作目录切换到根目录。如果是在一个临时加载的文件系统上执行这个进程的,比如:/mnt/floppy/,该进程的当前工作目录就会
是/mnt/floppy/。在整个进程运行期间该文件系统都无法被卸下(umount),而无论是否在使用这个文件系统,这会给带来很多不便。
解决的方法是使用chdir系统调用把当前工作目录变为根目录。当然,在这一步里,如果有特殊的需要,也可以把当前工作目录换成其他
的路径,如/tmp。
      (3)将文件权限掩码设为0。这需要调用系统调用umask。每个进程都会从父进程那里继承一个文件权限掩码,当创建新文件时,这个掩码
被用于设定文件的默认访问权限,屏蔽掉某些权限,如一般用户的写权限。当另一个进程用exec调用编写的daemon程序时,由于不知道那个
进程的文件权限掩码是什么,这样在创建新文件时,就会带来一些麻烦。所以应该重新设置文件权限掩码。可以将文件权限掩码设成任何值,
但一般情况下都把它设为0,这样它就不会屏蔽用户的任何操作。如果应用程序根本就不涉及创建新文件或是文件访问权限的设定,也完全
不管文件权限掩码,跳过这一步。
      (4)关闭所有不需要的文件。同文件权限掩码一样,新进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不被
daemon进程读或写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸下。在上面的第2步后,daemon进程已经与所属的控制
终端失去了联系,从终端输入的字符不可能达到daemon进程,daemon进程用常规的方法(如printf)输出的字符也不可能在终端上显示出来。
所以,文件描述符为0、1和2的三个文件,即常说的输入、输出和报错这三个文件已经失去了存在的价值,也应被关闭。

下面,看看一个daemon进程的诞生:
        // daemon.c
           #include
           #include
           #include
           #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            close(i);
        //
        到现在为止,进程已经成为一个完全的daemon进程,可以在这里添加任何要daemon做的事情,如:

          for(;;)
           sleep(10);
         }
       daemon进程不像其他进程一样有很明显的运行结果,但可以用"ps -ajx"命令观察一下daemon进程的状态和一些参数。

阅读(759) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~